Session SPARCv8

Theory WordDecl

(*  Title:     State.thy
    Author:    David Sanán, Trinity College Dublin, 2012
*)

section "Word Declarations"

theory WordDecl
imports Main "HOL-Library.Word"
begin

text ‹
This theory provides len0› and len› instantiations 
for the most common used word sizes in the model (1,2,4,5,6,8,12,16,18,20,24,32,36).
The len0› class defines lengths that range from 0 upwards,
whilst the len› class caters for non-zero lengths.
Bit-operators like <<›, >>›, and›, or or› 
require a'::len› word instances,
while other word operations such @{term "ucast"} 
(gets an integer from a word) 
can be defined for len0› words. 

For each length N›, we:
   declare a type word_lengthN›;
   make it an instance of both length classes;
   and introduce a short type synonym wordN›, and a suitable translation.

In essence, this theory is just a lot of boilerplate.
\newpage
›

section "Words of length 1"

typedecl word_length1
instantiation word_length1 :: len0
begin
definition
  len1 [simp]: "len_of (x::word_length1 itself)  1"
instance .. 
end
instantiation word_length1 :: len
begin
instance by intro_classes simp
end
type_synonym word1 = "word_length1 word"
translations (type) "word1" <= (type) "word_length1 word"

subsection "Words of length 1's constants"

definition ONE::"word1"
where
"ONE  1"

definition ZERO::"word1"
where
"ZERO  0"

section "Words of length 2"

typedecl word_length2
instantiation word_length2 :: len0
begin
definition
  len2 [simp]: "len_of (x::word_length2 itself)  2"
instance .. 
end
instantiation word_length2 :: len
begin
instance by intro_classes simp
end
type_synonym word2 = "word_length2 word"
translations (type) "word2" <= (type) "word_length2 word"

section "Words of length 3"

typedecl word_length3
instantiation word_length3 :: len0
begin
definition
  len3 [simp]: "len_of (x::word_length3 itself)  3"
instance .. 
end
instantiation word_length3 :: len
begin
instance by intro_classes simp
end
type_synonym word3 = "word_length3 word"
translations (type) "word3" <= (type) "word_length3 word"

section "Words of length 4"

typedecl word_length4
instantiation word_length4 :: len0
begin
definition
  len4 [simp]: "len_of (x::word_length4 itself)  4"
instance .. 
end
instantiation word_length4 :: len
begin
instance by intro_classes simp
end
type_synonym word4 = "word_length4 word"
translations (type) "word4" <= (type) "word_length4 word"

section "Words of length 5"

typedecl word_length5
instantiation word_length5 :: len0
begin
definition
  len5 [simp]: "len_of (x::word_length5 itself)  5"
instance .. 
end
instantiation word_length5 :: len
begin
instance by intro_classes simp
end
type_synonym word5 = "word_length5 word"
translations (type) "word5" <= (type) "word_length5 word"

section "Words of length 6"

typedecl word_length6
instantiation word_length6 :: len0
begin
definition
  len6 [simp]: "len_of (x::word_length6 itself)  6"
instance .. 
end
instantiation word_length6 :: len
begin
instance by intro_classes simp
end
type_synonym word6 = "word_length6 word"
translations (type) "word6" <= (type) "word_length6 word"

section "Words of length 6"

typedecl word_length7
instantiation word_length7 :: len0
begin
definition
  len7 [simp]: "len_of (x::word_length7 itself)  7"
instance .. 
end
instantiation word_length7 :: len
begin
instance by intro_classes simp
end
type_synonym word7 = "word_length7 word"
translations (type) "word7" <= (type) "word_length7 word"

section "Words of length 8"

typedecl word_length8
instantiation word_length8 :: len0
begin
definition
  len8 [simp]: "len_of (x::word_length8 itself)  8"
instance .. 
end
instantiation word_length8 :: len
begin
instance by intro_classes simp
end
type_synonym word8 = "word_length8 word"
translations (type) "word8" <= (type) "word_length8 word"

section "Words of length 9"

typedecl word_length9
instantiation word_length9 :: len0
begin
definition
  len9 [simp]: "len_of (x::word_length9 itself)  9"
instance .. 
end
instantiation word_length9 :: len
begin
instance by intro_classes simp
end
type_synonym word9 = "word_length9 word"
translations (type) "word9" <= (type) "word_length9 word"

section "Words of length 10"

typedecl word_length10
instantiation word_length10 :: len0
begin
definition
  len10 [simp]: "len_of (x::word_length10 itself)  10"
instance .. 
end
instantiation word_length10 :: len
begin
instance by intro_classes simp
end
type_synonym word10 = "word_length10 word"
translations (type) "word10" <= (type) "word_length10 word"

section "Words of length 12"

typedecl word_length12
instantiation word_length12 :: len0
begin
definition
  len12 [simp]: "len_of (x::word_length12 itself)  12"
instance .. 
end
instantiation word_length12 :: len
begin
instance by intro_classes simp
end
type_synonym word12 = "word_length12 word"
translations (type) "word12" <= (type) "word_length12 word"

section "Words of length 13"

typedecl word_length13
instantiation word_length13 :: len0
begin
definition
  len13 [simp]: "len_of (x::word_length13 itself)  13"
instance .. 
end
instantiation word_length13 :: len
begin
instance by intro_classes simp
end
type_synonym word13 = "word_length13 word"
translations (type) "word13" <= (type) "word_length13 word"

section "Words of length 16"

typedecl word_length16
instantiation word_length16 :: len0
begin
definition
  len16 [simp]: "len_of (x::word_length16 itself)  16"
instance .. 
end
instantiation word_length16 :: len
begin
instance by intro_classes simp
end
type_synonym word16 = "word_length16 word"
translations (type) "word16" <= (type) "word_length16 word"

section "Words of length 18"

typedecl word_length18
instantiation word_length18 :: len0
begin
definition
  len18 [simp]: "len_of (x::word_length18 itself)  18"
instance .. 
end
instantiation word_length18 :: len
begin
instance by intro_classes simp
end
type_synonym word18 = "word_length18 word"
translations (type) "word18" <= (type) "word_length18 word"

section "Words of length 20"

typedecl word_length20
instantiation word_length20 :: len0
begin
definition
  len20 [simp]: "len_of (x::word_length20 itself)  20"
instance .. 
end
instantiation word_length20 :: len
begin
instance by intro_classes simp
end
type_synonym word20 = "word_length20 word"
translations (type) "word20" <= (type) "word_length20 word"

section "Words of length 22"

typedecl word_length22
instantiation word_length22 :: len0
begin
definition
  len22 [simp]: "len_of (x::word_length22 itself)  22"
instance .. 
end
instantiation word_length22 :: len
begin
instance by intro_classes simp
end
type_synonym word22 = "word_length22 word"
translations (type) "word22" <= (type) "word_length22 word"

section "Words of length 24"

typedecl word_length24
instantiation word_length24 :: len0
begin
definition
  len24 [simp]: "len_of (x::word_length24 itself)  24"
instance .. 
end
instantiation word_length24 :: len
begin
instance by intro_classes simp
end
type_synonym word24 = "word_length24 word"
translations (type) "word24" <= (type) "word_length24 word"

section "Words of length 30"

typedecl word_length30
instantiation word_length30 :: len0
begin
definition
  len30 [simp]: "len_of (x::word_length30 itself)  30"
instance .. 
end
instantiation word_length30 :: len
begin
instance by intro_classes simp
end
type_synonym word30 = "word_length30 word"
translations (type) "word30" <= (type) "word_length30 word"

section "Words of length 30"

typedecl word_length31
instantiation word_length31 :: len0
begin
definition
  len31 [simp]: "len_of (x::word_length31 itself)  31"
instance .. 
end
instantiation word_length31 :: len
begin
instance by intro_classes simp
end
type_synonym word31 = "word_length31 word"
translations (type) "word31" <= (type) "word_length31 word"

section "Words of length 32"

typedecl word_length32
instantiation word_length32 :: len0
begin
definition
  len32 [simp]: "len_of (x::word_length32 itself)  32"
instance .. 
end
instantiation word_length32 :: len
begin                            
instance by intro_classes simp
end
type_synonym word32 = "word_length32 word"
translations (type) "word32" <= (type) "word_length32 word"

section "Words of length 33"

typedecl word_length33
instantiation word_length33 :: len0
begin
definition
  len33 [simp]: "len_of (x::word_length33 itself)  33"
instance .. 
end
instantiation word_length33 :: len
begin                            
instance by intro_classes simp
end
type_synonym word33 = "word_length33 word"
translations (type) "word33" <= (type) "word_length33 word"

section "Words of length 36"

typedecl word_length36
instantiation word_length36 :: len0
begin
definition
  len36 [simp]: "len_of (x::word_length36 itself)  36"
instance ..
end
instantiation word_length36 :: len
begin
  instance by intro_classes simp
end
type_synonym word36 = "word_length36 word"
translations (type) "word36" <= (type) "word_length36 word"

section "Words of length 64"

typedecl word_length64
instantiation word_length64 :: len0
begin
definition
  len64 [simp]: "len_of (x::word_length64 itself)  64"
instance ..
end
instantiation word_length64 :: len
begin
  instance by intro_classes simp
end
type_synonym word64 = "word_length64 word"
translations (type) "word64" <= (type) "word_length64 word"

end



Theory Sparc_Types

(*
 * Copyright 2016, NTU
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * Author: Zhe Hou, David Sanan. 
 *)

section ‹SPARC V8 architecture CPU model›
theory Sparc_Types    
imports Main "../lib/WordDecl" "Word_Lib.Traditional_Infix_Syntax"
begin

text ‹The following type definitions are taken from David Sanan's 
definitions for SPARC machines.›

type_synonym machine_word = word32
type_synonym byte = word8
type_synonym phys_address = word36

type_synonym virtua_address = word32
type_synonym page_address = word24
type_synonym offset = word12

type_synonym table_entry = word8

definition page_size :: "word32" where "page_size  4096"

type_synonym virtua_page_address = word20
type_synonym context_type = word8

type_synonym word_length_t1 = word_length8
type_synonym word_length_t2 = word_length6
type_synonym word_length_t3 = word_length6
type_synonym word_length_offset = word_length12
type_synonym word_length_page = word_length24
type_synonym word_length_phys_address = word_length36
type_synonym word_length_virtua_address = word_length32
type_synonym word_length_entry_type = word_length2
type_synonym word_length_machine_word = word_length32

definition length_machine_word :: "nat" 
 where "length_machine_word  LENGTH(word_length_machine_word)"

text_raw ‹\newpage›

section ‹CPU Register Definitions›

text‹
 The definitions below come from the SPARC Architecture Manual, Version 8.
 The LEON3 processor has been certified SPARC V8 conformant (2005).
›

definition leon3khz ::"word32"
where
"leon3khz  33000"

text ‹The following type definitions for MMU is taken from 
David Sanan's definitions for MMU.›

text‹
  The definitions below come from the UT699 LEON 3FT/SPARC V8 Microprocessor Functional Manual, 
   Aeroflex, June 20, 2012, p35.
›
datatype MMU_register
 = CR    ― ‹Control Register›
 | CTP   ― ‹ConText Pointer register›
 | CNR   ― ‹Context Register›
 | FTSR   ― ‹Fault Status Register›
 | FAR   ― ‹Fault Address Register›

lemma MMU_register_induct: 
  "P CR  P CTP  P CNR  P FTSR  P FAR 
    P x"
  by (cases x) auto

lemma UNIV_MMU_register [no_atp]: "UNIV = {CR, CTP, CNR, FTSR, FAR}"
   apply (safe)
   apply (case_tac x)
   apply (auto intro:MMU_register_induct)
  done


instantiation MMU_register :: enum begin

definition "enum_MMU_register = [ CR, CTP, CNR, FTSR, FAR ]"

definition
  "enum_all_MMU_register P  P CR  P CTP  P CNR  P FTSR  P FAR "
definition
  "enum_ex_MMU_register P  P CR  P CTP  P CNR  P FTSR  P FAR"

 instance proof
  qed (simp_all only: enum_MMU_register_def enum_all_MMU_register_def 
                      enum_ex_MMU_register_def UNIV_MMU_register, simp_all)
end
type_synonym MMU_context = "MMU_register  machine_word"

text PTE_flags› is the last 8 bits of a PTE. See page 242 of SPARCv8 manual.
 C - bit 7
 M - bit 6,
 R - bit 5
 ACC - bit 4~2
 ET - bit 1~0.›

type_synonym PTE_flags = word8

text @{term CPU_register} datatype is an enumeration with the CPU registers defined in the SPARC V8 
  architecture.
›
datatype CPU_register = 
   PSR   ― ‹Processor State Register›
 | WIM   ― ‹Window Invalid Mask›
 | TBR   ― ‹Trap Base Register›
 | Y     ― ‹Multiply/Divide Register›
 | PC    ― ‹Program Counter›
 | nPC   ― ‹next Program Counter›
 | DTQ   ― ‹Deferred-Trap Queue›
 | FSR   ― ‹Floating-Point State Register›
 | FQ    ― ‹Floating-Point Deferred-Trap Queue›
 | CSR   ― ‹Coprocessor State Register›
 | CQ    ― ‹Coprocessor Deferred-Trap Queue›
 (*| CCR   --   "Cache Control Register"*)
 | ASR "word5"  ― ‹Ancillary State Register›

text ‹The following two functions are dummies since we will not use 
        ASRs. Future formalisation may add more details to this.›

definition privileged_ASR :: "word5  bool"
where
"privileged_ASR r  False
"

definition illegal_instruction_ASR :: "word5  bool"
where
"illegal_instruction_ASR r  False
"

definition get_tt :: "word32  word8"
where
"get_tt tbr 
  ucast (((AND) tbr 0b00000000000000000000111111110000) >> 4)
"

text ‹Write the tt field of the TBR register. 
        Return the new value of TBR.›
definition write_tt :: "word8  word32  word32"
where
"write_tt new_tt_val tbr_val 
  let tmp = (AND) tbr_val 0b111111111111111111111000000001111 in
      (OR) tmp (((ucast new_tt_val)::word32) << 4)
"

text ‹Get the nth bit of WIM. This equals ((AND) WIM $2^n$). 
        N.B. the first bit of WIM is the 0th bit.›
definition get_WIM_bit :: "nat  word32  word1"
where
"get_WIM_bit n wim 
  let mask = ((ucast (0b1::word1))::word32) << n in
  ucast (((AND) mask wim) >> n)
"

definition get_CWP :: "word32  word5"
where
"get_CWP psr  
  ucast ((AND) psr 0b00000000000000000000000000011111) 
"

definition get_ET :: "word32  word1"
where
"get_ET psr  
  ucast (((AND) psr 0b00000000000000000000000000100000) >> 5) 
"

definition get_PIL :: "word32  word4"
where
"get_PIL psr  
  ucast (((AND) psr 0b00000000000000000000111100000000) >> 8) 
"

definition get_PS :: "word32  word1"
where
"get_PS psr  
  ucast (((AND) psr 0b00000000000000000000000001000000) >> 6) 
"

definition get_S :: "word32  word1"
where
"get_S psr  
  ⌦‹ucast (((AND) psr 0b00000000000000000000000010000000) >> 7)›
  if ((AND) psr (0b00000000000000000000000010000000::word32)) = 0 then 0
  else 1
"

definition get_icc_N :: "word32  word1"
where
"get_icc_N psr 
  ucast (((AND) psr 0b00000000100000000000000000000000) >> 23)
"

definition get_icc_Z :: "word32  word1"
where
"get_icc_Z psr 
  ucast (((AND) psr 0b00000000010000000000000000000000) >> 22)
"

definition get_icc_V :: "word32  word1"
where
"get_icc_V psr 
  ucast (((AND) psr 0b00000000001000000000000000000000) >> 21)
"

definition get_icc_C :: "word32  word1"
where
"get_icc_C psr 
  ucast (((AND) psr 0b00000000000100000000000000000000) >> 20)
"

definition update_S :: "word1  word32  word32"
where
"update_S s_val psr_val 
  let tmp0 = (AND) psr_val 0b11111111111111111111111101111111 in
  (OR) tmp0 (((ucast s_val)::word32) << 7)
"

text ‹Update the CWP field of PSR. 
        Return the new value of PSR.›
definition update_CWP :: "word5  word32  word32"
where
"update_CWP cwp_val psr_val 
  let tmp0 = (AND) psr_val (0b11111111111111111111111111100000::word32);
      s_val = ((ucast (get_S psr_val))::word1)
  in
  if s_val = 0 then  
    (AND) ((OR) tmp0 ((ucast cwp_val)::word32)) (0b11111111111111111111111101111111::word32)
  else
    (OR) ((OR) tmp0 ((ucast cwp_val)::word32)) (0b00000000000000000000000010000000::word32)
"

text ‹Update the the ET, CWP, and S fields of PSR. 
        Return the new value of PSR.›
definition update_PSR_rett :: "word5  word1  word1  word32  word32"
where
"update_PSR_rett cwp_val et_val s_val psr_val 
  let tmp0 = (AND) psr_val 0b11111111111111111111111101000000;
      tmp1 = (OR) tmp0 ((ucast cwp_val)::word32);
      tmp2 = (OR) tmp1 (((ucast et_val)::word32) << 5); 
      tmp3 = (OR) tmp2 (((ucast s_val)::word32) << 7)
  in  
  tmp3
"

definition update_PSR_exe_trap :: "word5  word1  word1  word32  word32"
where
"update_PSR_exe_trap cwp_val et_val ps_val psr_val 
  let tmp0 = (AND) psr_val 0b11111111111111111111111110000000;
      tmp1 = (OR) tmp0 ((ucast cwp_val)::word32);
      tmp2 = (OR) tmp1 (((ucast et_val)::word32) << 5); 
      tmp3 = (OR) tmp2 (((ucast ps_val)::word32) << 6)
  in  
  tmp3
"

text ‹Update the N, Z, V, C fields of PSR. 
        Return the new value of PSR.›
definition update_PSR_icc :: "word1  word1  word1  word1  word32  word32"
where
"update_PSR_icc n_val z_val v_val c_val psr_val 
  let
      n_val_32 = if n_val = 0 then 0 
                 else       (0b00000000100000000000000000000000::word32); 
      z_val_32 = if z_val = 0 then 0 
                 else       (0b00000000010000000000000000000000::word32); 
      v_val_32 = if v_val = 0 then 0 
                 else       (0b00000000001000000000000000000000::word32);
      c_val_32 = if c_val = 0 then 0 
                 else       (0b00000000000100000000000000000000::word32);
      tmp0 = (AND) psr_val (0b11111111000011111111111111111111::word32);
      tmp1 = (OR) tmp0 n_val_32;
      tmp2 = (OR) tmp1 z_val_32;
      tmp3 = (OR) tmp2 v_val_32;
      tmp4 = (OR) tmp3 c_val_32
  in
  tmp4
"

text ‹Update the ET, PIL fields of PSR. 
        Return the new value of PSR.›
definition update_PSR_et_pil :: "word1  word4  word32  word32"
where
"update_PSR_et_pil et pil psr_val 
  let tmp0 = (AND) psr_val 0b111111111111111111111000011011111;
      tmp1 = (OR) tmp0 (((ucast et)::word32) << 5);
      tmp2 = (OR) tmp1 (((ucast pil)::word32) << 8)
  in
  tmp2
"

text ‹
   SPARC V8 architecture is organized in windows of 32 user registers.
   The data stored in a register is defined as a 32 bits word @{term reg_type}:
›
type_synonym reg_type = "word32"

text ‹
  The access to the value of a CPU register of type @{term CPU_register} is
  defined by a total function @{term cpu_context}

type_synonym cpu_context = "CPU_register  reg_type"

text ‹
  User registers are defined with the type @{term user_reg} represented by a 5 bits word.
›

type_synonym user_reg_type = "word5"

definition PSR_S ::"reg_type"
where "PSR_S  6"
text ‹
  Each window context is defined by a total function @{term window_context} from @{term user_register} 
  to @{term reg_type} (32 bits word storing the actual value of the register).
›

type_synonym window_context = "user_reg_type  reg_type"
text ‹
  The number of windows is implementation dependent. 
  The LEON architecture is composed of 16 different windows (a 4 bits word).
›

definition NWINDOWS :: "int"
where "NWINDOWS  8"

text ‹Maximum number of windows is 32 in SPARCv8.›
type_synonym ('a) window_size = "'a word"

text ‹
Finally the user context is defined by another total function @{term user_context} from 
@{term window_size} to @{term window_context}. That is, the user context is a function taking as
argument a register set window and a register within that window, and it returns the value stored
in that user register.
›
type_synonym ('a) user_context = "('a) window_size  window_context"

datatype sys_reg = 
         CCR    ― ‹Cache control register›
        |ICCR   ― ‹Instruction cache configuration register›
        |DCCR   ― ‹Data cache configuration register›

type_synonym sys_context = "sys_reg  reg_type"

text‹
The memory model is defined by a total function from 32 bits words to 8 bits words
›
type_synonym asi_type = "word8"

text ‹
 The memory is defined as a function from page address to page, which is also defined
  as a function from physical address to @{term "machine_word"}

type_synonym mem_val_type = "word8"
type_synonym mem_context = "asi_type  phys_address  mem_val_type option"

type_synonym cache_tag = "word20"
type_synonym cache_line_size = "word12"
type_synonym cache_type = "(cache_tag × cache_line_size)"
type_synonym cache_context = "cache_type  mem_val_type option"

text ‹The delayed-write pool generated from write state register instructions.›
type_synonym delayed_write_pool = "(int × reg_type × CPU_register) list"

definition DELAYNUM :: "int"
where "DELAYNUM  0"

text ‹Convert a set to a list.›
definition list_of_set :: "'a set  'a list"
  where "list_of_set s = (SOME l. set l = s)"

lemma set_list_of_set: "finite s  set (list_of_set s) = s"
unfolding list_of_set_def 
by (metis (mono_tags) finite_list some_eq_ex)

type_synonym ANNUL = "bool"
type_synonym RESET_TRAP = "bool"
type_synonym EXECUTE_MODE = "bool"
type_synonym RESET_MODE = "bool"
type_synonym ERROR_MODE = "bool"
type_synonym TICC_TRAP_TYPE = "word7"
type_synonym INTERRUPT_LEVEL = "word3"
type_synonym STORE_BARRIER_PENDING = "bool"

text ‹The processor asserts this signal to ensure that the
memory system will not process another SWAP or
LDSTUB operation to the same memory byte.›
type_synonym pb_block_ldst_byte = "virtua_address  bool"

text‹The processor asserts this signal to ensure that the
memory system will not process another SWAP or
LDSTUB operation to the same memory word.›
type_synonym pb_block_ldst_word = "virtua_address  bool"

record sparc_state_var =
annul:: ANNUL
resett:: RESET_TRAP
exe:: EXECUTE_MODE
reset:: RESET_MODE
err:: ERROR_MODE
ticc:: TICC_TRAP_TYPE
itrpt_lvl:: INTERRUPT_LEVEL
st_bar:: STORE_BARRIER_PENDING
atm_ldst_byte:: pb_block_ldst_byte
atm_ldst_word:: pb_block_ldst_word

definition get_annul :: "sparc_state_var  bool"
where "get_annul v  annul v"

definition get_reset_trap :: "sparc_state_var  bool"
where "get_reset_trap v  resett v"

definition get_exe_mode :: "sparc_state_var  bool"
where "get_exe_mode v  exe v"

definition get_reset_mode :: "sparc_state_var  bool"
where "get_reset_mode v  reset v"

definition get_err_mode :: "sparc_state_var  bool"
where "get_err_mode v  err v"

definition get_ticc_trap_type :: "sparc_state_var  word7"
where "get_ticc_trap_type v  ticc v"

definition get_interrupt_level :: "sparc_state_var  word3"
where "get_interrupt_level v  itrpt_lvl v"

definition get_store_barrier_pending :: "sparc_state_var  bool"
where "get_store_barrier_pending v  st_bar v"

definition write_annul :: "bool  sparc_state_var  sparc_state_var"
where "write_annul b v  vannul := b"

definition write_reset_trap :: "bool  sparc_state_var  sparc_state_var"
where "write_reset_trap b v  vresett := b"

definition write_exe_mode :: "bool  sparc_state_var  sparc_state_var"
where "write_exe_mode b v  vexe := b"

definition write_reset_mode :: "bool  sparc_state_var  sparc_state_var"
where "write_reset_mode b v  vreset := b"

definition write_err_mode :: "bool  sparc_state_var  sparc_state_var"
where "write_err_mode b v  verr := b"

definition write_ticc_trap_type :: "word7  sparc_state_var  sparc_state_var"
where "write_ticc_trap_type w v  vticc := w"

definition write_interrupt_level :: "word3  sparc_state_var  sparc_state_var"
where "write_interrupt_level w v  vitrpt_lvl := w"

definition write_store_barrier_pending :: "bool  sparc_state_var  sparc_state_var"
where "write_store_barrier_pending b v  vst_bar := b"

text ‹Given a word7 value, find the highest bit,
        and fill the left bits to be the highest bit.›
definition sign_ext7::"word7  word32"
where
"sign_ext7 w  
  let highest_bit = ((AND) w 0b1000000) >> 6 in
  if highest_bit = 0 then
    (ucast w)::word32
  else (OR) ((ucast w)::word32) 0b11111111111111111111111110000000
"

definition zero_ext8 :: "word8  word32"
where
"zero_ext8 w  (ucast w)::word32
"

text ‹Given a word8 value, find the highest bit,
        and fill the left bits to be the highest bit.›
definition sign_ext8::"word8  word32"
where
"sign_ext8 w  
  let highest_bit = ((AND) w 0b10000000) >> 7 in
  if highest_bit = 0 then
    (ucast w)::word32
  else (OR) ((ucast w)::word32) 0b11111111111111111111111100000000
"

text ‹Given a word13 value, find the highest bit,
        and fill the left bits to be the highest bit.›
definition sign_ext13::"word13  word32"
where
"sign_ext13 w  
  let highest_bit = ((AND) w 0b1000000000000) >> 12 in
  if highest_bit = 0 then
    (ucast w)::word32
  else (OR) ((ucast w)::word32) 0b11111111111111111110000000000000
"

definition zero_ext16 :: "word16  word32"
where
"zero_ext16 w  (ucast w)::word32
"

text ‹Given a word16 value, find the highest bit,
        and fill the left bits to be the highest bit.›
definition sign_ext16::"word16  word32"
where
"sign_ext16 w  
  let highest_bit = ((AND) w 0b1000000000000000) >> 15 in
  if highest_bit = 0 then
    (ucast w)::word32
  else (OR) ((ucast w)::word32) 0b11111111111111110000000000000000
"

text ‹Given a word22 value, find the highest bit,
        and fill the left bits to tbe the highest bit.›
definition sign_ext22::"word22  word32"
where
"sign_ext22 w 
  let highest_bit = ((AND) w 0b1000000000000000000000) >> 21 in
  if highest_bit = 0 then
    (ucast w)::word32
  else (OR) ((ucast w)::word32) 0b11111111110000000000000000000000
"

text ‹Given a word24 value, find the highest bit,
        and fill the left bits to tbe the highest bit.›
definition sign_ext24::"word24  word32"
where
"sign_ext24 w 
  let highest_bit = ((AND) w 0b100000000000000000000000) >> 23 in
  if highest_bit = 0 then
    (ucast w)::word32
  else (OR) ((ucast w)::word32) 0b11111111000000000000000000000000
"

text‹
Operations to be defined.
The SPARC V8 architecture is composed of the following set of instructions:
   Load Integer Instructions
   Load Floating-point Instructions
   Load Coprocessor Instructions
   Store Integer Instructions
   Store Floating-point Instructions
   Store Coprocessor Instructions
   Atomic Load-Store Unsigned Byte Instructions
   SWAP Register With Memory Instruction
   SETHI Instructions
   NOP Instruction
   Logical Instructions
   Shift Instructions
   Add Instructions
   Tagged Add Instructions
   Subtract Instructions
   Tagged Subtract Instructions
   Multiply Step Instruction
   Multiply Instructions
   Divide Instructions
   SAVE and RESTORE Instructions
   Branch on Integer Condition Codes Instructions
   Branch on Floating-point Condition Codes Instructions
   Branch on Coprocessor Condition Codes Instructions
   Call and Link Instruction
   Jump and Link Instruction
   Return from Trap Instruction
   Trap on Integer Condition Codes Instructions
   Read State Register Instructions
   Write State Register Instructions
   STBAR Instruction
   Unimplemented Instruction
   Flush Instruction Memory
   Floating-point Operate (FPop) Instructions
   Convert Integer to Floating point Instructions
   Convert Floating point to Integer Instructions
   Convert Between Floating-point Formats Instructions
   Floating-point Move Instructions
   Floating-point Square Root Instructions
   Floating-point Add and Subtract Instructions
   Floating-point Multiply and Divide Instructions
   Floating-point Compare Instructions
   Coprocessor Operate Instructions
›

text ‹The CALL instruction.›
datatype call_type = CALL ― ‹Call and Link›

text ‹The SETHI instruction.›
datatype sethi_type = SETHI    ― ‹Set High 22 bits of r Register›

text ‹The NOP instruction.›
datatype nop_type = NOP      ― ‹No Operation›

text ‹The Branch on integer condition codes instructions.› 
datatype bicc_type = 
  BE       ― ‹Branch on Equal›
 | BNE      ― ‹Branch on Not Equal›
 | BGU      ― ‹Branch on Greater Unsigned›
 | BLE      ― ‹Branch on Less or Equal›
 | BL       ― ‹Branch on Less›
 | BGE      ― ‹Branch on Greater or Equal›
 | BNEG     ― ‹Branch on Negative›
 | BG       ― ‹Branch on Greater›
 | BCS      ― ‹Branch on Carry Set (Less than, Unsigned)›
 | BLEU     ― ‹Branch on Less or Equal Unsigned›
 | BCC      ― ‹Branch on Carry Clear (Greater than or Equal, Unsigned)›
 | BA       ― ‹Branch Always›
 | BN       ― ‹Branch Never› ― ‹Added for unconditional branches›
 | BPOS     ― ‹Branch on Positive›
 | BVC      ― ‹Branch on Overflow Clear›
 | BVS      ― ‹Branch on Overflow Set›

text ‹Memory instructions. That is, load and store.›
datatype load_store_type =
  LDSB     ― ‹Load Signed Byte›
 | LDUB     ― ‹Load Unsigned Byte›
 | LDUBA    ― ‹Load Unsigned Byte from Alternate space›
 | LDUH     ― ‹Load Unsigned Halfword›
 | LD       ― ‹Load Word›
 | LDA      ― ‹Load Word from Alternate space›
 | LDD      ― ‹Load Doubleword›
 | STB      ― ‹Store Byte›
 | STH      ― ‹Store Halfword›
 | ST       ― ‹Store Word›
 | STA      ― ‹Store Word into Alternate space›
 | STD      ― ‹Store Doubleword›
 | LDSBA    ― ‹Load Signed Byte from Alternate space›
 | LDSH     ― ‹Load Signed Halfword›
 | LDSHA    ― ‹Load Signed Halfword from Alternate space›
 | LDUHA    ― ‹Load Unsigned Halfword from Alternate space›
 | LDDA     ― ‹Load Doubleword from Alternate space›
 | STBA     ― ‹Store Byte into Alternate space›
 | STHA     ― ‹Store Halfword into Alternate space›
 | STDA     ― ‹Store Doubleword into Alternate space›
 | LDSTUB   ― ‹Atomic Load Store Unsigned Byte›
 | LDSTUBA  ― ‹Atomic Load Store Unsinged Byte in Alternate space›
 | SWAP     ― ‹Swap r Register with Mmemory›
 | SWAPA    ― ‹Swap r Register with Mmemory in Alternate space›
 | FLUSH    ― ‹Flush Instruction Memory›
 | STBAR    ― ‹Store Barrier›

text ‹Arithmetic instructions.›
datatype arith_type =
  ADD      ― ‹Add›
 | ADDcc    ― ‹Add and modify icc›
 | ADDX     ― ‹Add with Carry›
 | SUB      ― ‹Subtract›
 | SUBcc    ― ‹Subtract and modify icc›
 | SUBX     ― ‹Subtract with Carry›
 | UMUL     ― ‹Unsigned Integer Multiply›
 | SMUL     ― ‹Signed Integer Multiply›
 | SMULcc   ― ‹Signed Integer Multiply and modify icc›
 | UDIV     ― ‹Unsigned Integer Divide›
 | UDIVcc   ― ‹Unsigned Integer Divide and modify icc›
 | SDIV     ― ‹Signed Integer Divide› 
 | ADDXcc   ― ‹Add with Carry and modify icc›
 | TADDcc   ― ‹Tagged Add and modify icc›
 | TADDccTV ― ‹Tagged Add and modify icc and Trap on overflow›
 | SUBXcc   ― ‹Subtract with Carry and modify icc›
 | TSUBcc   ― ‹Tagged Subtract and modify icc›
 | TSUBccTV ― ‹Tagged Subtract and modify icc and Trap on overflow›
 | MULScc   ― ‹Multiply Step and modify icc›
 | UMULcc   ― ‹Unsigned Integer Multiply and modify icc›
 | SDIVcc   ― ‹Signed Integer Divide and modify icc›

text ‹Logical instructions.›
datatype logic_type =
  ANDs      ― ‹And›
 | ANDcc    ― ‹And and modify icc›
 | ANDN     ― ‹And Not›
 | ANDNcc   ― ‹And Not and modify icc›
 | ORs       ― ‹Inclusive-Or›
 | ORcc     ― ‹Inclusive-Or and modify icc›
 | ORN      ― ‹Inclusive Or Not›
 | XORs      ― ‹Exclusive-Or›
 | XNOR     ― ‹Exclusive-Nor›
 | ORNcc    ― ‹Inclusive-Or Not and modify icc›
 | XORcc    ― ‹Exclusive-Or and modify icc›
 | XNORcc   ― ‹Exclusive-Nor and modify icc›
 
text ‹Shift instructions.›
datatype shift_type =
  SLL      ― ‹Shift Left Logical›
 | SRL      ― ‹Shift Right Logical›
 | SRA      ― ‹Shift Right Arithmetic› 

text ‹Other Control-transfer instructions.›
datatype ctrl_type = 
  JMPL     ― ‹Jump and Link›
 | RETT     ― ‹Return from Trap›
 | SAVE     ― ‹Save caller's window›
 | RESTORE  ― ‹Restore caller's window› 

text ‹Access state registers instructions.›
datatype sreg_type =
  RDASR    ― ‹Read Ancillary State Register›
 | RDY      ― ‹Read Y Register›
 | RDPSR    ― ‹Read Processor State Register›
 | RDWIM    ― ‹Read Window Invalid Mask Register›
 | RDTBR    ― ‹Read Trap Base Regiser›
 | WRASR    ― ‹Write Ancillary State Register›
 | WRY      ― ‹Write Y Register›
 | WRPSR    ― ‹Write Processor State Register›
 | WRWIM    ― ‹Write Window Invalid Mask Register›
 | WRTBR    ― ‹Write Trap Base Register› 

text ‹Unimplemented instruction.›
datatype uimp_type = UNIMP    ― ‹Unimplemented› 

text ‹Trap on integer condition code instructions.›
datatype ticc_type =
 TA       ― ‹Trap Always›
 | TN       ― ‹Trap Never›
 | TNE      ― ‹Trap on Not Equal›
 | TE       ― ‹Trap on Equal›
 | TG       ― ‹Trap on Greater›
 | TLE      ― ‹Trap on Less or Equal›
 | TGE      ― ‹Trap on Greater or Equal›
 | TL       ― ‹Trap on Less›
 | TGU      ― ‹Trap on Greater Unsigned›
 | TLEU     ― ‹Trap on Less or Equal Unsigned›
 | TCC      ― ‹Trap on Carry Clear (Greater than or Equal, Unsigned)›
 | TCS      ― ‹Trap on Carry Set (Less Than, Unsigned)›
 | TPOS     ― ‹Trap on Postive›
 | TNEG     ― ‹Trap on Negative›
 | TVC      ― ‹Trap on Overflow Clear›
 | TVS      ― ‹Trap on Overflow Set›

datatype sparc_operation =
  call_type call_type
 | sethi_type sethi_type
 | nop_type nop_type
 | bicc_type bicc_type
 | load_store_type load_store_type
 | arith_type arith_type
 | logic_type logic_type
 | shift_type shift_type
 | ctrl_type ctrl_type
 | sreg_type sreg_type
 | uimp_type uimp_type
 | ticc_type ticc_type

datatype Trap = 
reset 
|data_store_error
|instruction_access_MMU_miss
|instruction_access_error
|r_register_access_error
|instruction_access_exception
|privileged_instruction
|illegal_instruction
|unimplemented_FLUSH
|watchpoint_detected
|fp_disabled
|cp_disabled
|window_overflow
|window_underflow
|mem_address_not_aligned
|fp_exception
|cp_exception
|data_access_error
|data_access_MMU_miss
|data_access_exception
|tag_overflow
|division_by_zero
|trap_instruction
|interrupt_level_n

datatype Exception =
― ‹The following are processor states that are not in the instruction model,›
― ‹but we MAY want to deal with these from hardware perspective.›
⌦‹|execute_mode›
⌦‹|reset_mode›
⌦‹|error_mode›
― ‹The following are self-defined exceptions.›
invalid_cond_f2
|invalid_op2_f2
|illegal_instruction2 ― ‹when i = 0› for load/store not from alternate space›
|invalid_op3_f3_op11
|case_impossible
|invalid_op3_f3_op10
|invalid_op_f3
|unsupported_instruction
|fetch_instruction_error
|invalid_trap_cond

end

Theory Lib

(*
 * Copyright 2014, NICTA
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * @TAG(NICTA_BSD)
 *)

(*
   Miscellaneous library definitions and lemmas.
*)

(*chapter "Library"*)

theory Lib
imports Main
begin

lemma hd_map_simp:
  "b  []  hd (map a b) = a (hd b)"
  by (rule hd_map)

lemma tl_map_simp:
  "tl (map a b) = map a (tl b)"
  by (induct b,auto)

lemma Collect_eq:
  "{x. P x} = {x. Q x}  (x. P x = Q x)"
  by (rule iffI) auto

lemma iff_impI: "P  Q = R  (P  Q) = (P  R)" by blast

definition
  fun_app :: "('a  'b)  'a  'b" (infixr "$" 10) where
  "f $ x  f x"

declare fun_app_def [iff]

lemma fun_app_cong[fundef_cong]:
  " f x = f' x'   (f $ x) = (f' $ x')"
  by simp

lemma fun_app_apply_cong[fundef_cong]:
  "f x y = f' x' y'  (f $ x) y = (f' $ x') y'"
  by simp

lemma if_apply_cong[fundef_cong]:
  " P = P'; x = x'; P'  f x' = f' x'; ¬ P'  g x' = g' x' 
      (if P then f else g) x = (if P' then f' else g') x'"
  by simp

abbreviation (input) split :: "('a  'b  'c)  'a × 'b  'c" where
  "split  case_prod"

lemma split_apply_cong[fundef_cong]:
  " f (fst p) (snd p) s = f' (fst p') (snd p') s'   split f p s = split f' p' s'"
  by (simp add: split_def)

definition
  pred_conj :: "('a  bool)  ('a  bool)  ('a  bool)" (infixl "and" 35)
where
  "pred_conj P Q  λx. P x  Q x"

definition
  pred_disj :: "('a  bool)  ('a  bool)  ('a  bool)" (infixl "or" 30)
where
  "pred_disj P Q  λx. P x  Q x"

definition
  pred_neg :: "('a  bool)  ('a  bool)" ("not _" [40] 40)
where
  "pred_neg P  λx. ¬ P x"

definition "K  λx y. x"

definition
  zipWith :: "('a  'b  'c)  'a list  'b list  'c list" where
  "zipWith f xs ys  map (split f) (zip xs ys)"

primrec
  delete :: "'a  'a list  'a list"
where
  "delete y [] = []"
| "delete y (x#xs) = (if y=x then xs else x # delete y xs)"

primrec
  find :: "('a  bool)  'a list  'a option"
where
  "find f [] = None"
| "find f (x # xs) = (if f x then Some x else find f xs)"

definition
 "swp f  λx y. f y x"

primrec (nonexhaustive)
  theRight :: "'a + 'b  'b" where
  "theRight (Inr x) = x"

primrec (nonexhaustive)
  theLeft :: "'a + 'b  'a" where
  "theLeft (Inl x) = x"

definition
 "isLeft x  (y. x = Inl y)"

definition
 "isRight x  (y. x = Inr y)"

definition
 "const x  λy. x"

lemma tranclD2:
  "(x, y)  R+  z. (x, z)  R*  (z, y)  R"
  by (erule tranclE) auto

lemma linorder_min_same1 [simp]:
  "(min y x = y) = (y  (x::'a::linorder))"
  by (auto simp: min_def linorder_not_less)

lemma linorder_min_same2 [simp]:
  "(min x y = y) = (y  (x::'a::linorder))"
  by (auto simp: min_def linorder_not_le)

text ‹A combinator for pairing up well-formed relations.
        The divisor function splits the population in halves,
        with the True half greater than the False half, and
        the supplied relations control the order within the halves.›

definition
  wf_sum :: "('a  bool)  ('a × 'a) set  ('a × 'a) set  ('a × 'a) set"
where
  "wf_sum divisor r r' 
     ({(x, y). ¬ divisor x  ¬ divisor y}  r')
     {(x, y). ¬ divisor x  divisor y}
    ({(x, y). divisor x  divisor y}  r)"

lemma wf_sum_wf:
  " wf r; wf r'   wf (wf_sum divisor r r')"
  apply (simp add: wf_sum_def)
  apply (rule wf_Un)+
      apply (erule wf_Int2)
     apply (rule wf_subset
             [where r="measure (λx. If (divisor x) 1 0)"])
      apply simp
     apply clarsimp
    apply blast
   apply (erule wf_Int2)
  apply blast
  done

abbreviation(input)
 "option_map == map_option"

lemmas option_map_def = map_option_case

lemma False_implies_equals [simp]:
  "((False  P)  PROP Q)  PROP Q"
  apply (rule equal_intr_rule)
   apply (erule meta_mp)
   apply simp
  apply simp
  done

lemma split_paired_Ball:
  "(x  A. P x) = (x y. (x,y)  A  P (x,y))"
  by auto

lemma split_paired_Bex:
  "(x  A. P x) = (x y. (x,y)  A  P (x,y))"
  by auto

end

Theory DetMonad

(*
 * Copyright 2014, NICTA
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * @TAG(NICTA_BSD)
 *)

(*
* Zhe Hou: I modified this file to model a deterministic monad instead of
* a non-deterministic monad. Features that are irrelevant to deterministic 
* moands are removed. I also removed the section for loops, which are not
* used in the modelling of the SPARC architecture.
*)

(* 
   Deterministic state and error monads with failure in Isabelle.
*)

(*chapter "Deterministic State Monad with Failure"*)

theory DetMonad
imports "../Lib"
begin

text ‹
  \label{c:monads}

  State monads are used extensively in the seL4 specification. They are
  defined below.
›

section "The Monad"

text ‹
  The basic type of the deterministic state monad with failure is
  very similar to the normal state monad. Instead of a pair consisting
  of result and new state, we return a pair coupled with
  a failure flag. The flag is @{const True} if the computation have failed. 
  Conversely, if the flag is @{const False}, the computation resulting in 
  the returned result have succeeded.› 
type_synonym ('s,'a) det_monad = "'s  ('a × 's) × bool"


text ‹
  The definition of fundamental monad functions return› and
  bind›. The monad function return x› does not change 
  the  state, does not fail, and returns x›.
› 
definition
  return :: "'a  ('s,'a) det_monad" where
  "return a  λs. ((a,s),False)"

text ‹
  The monad function bind f g›, also written f >>= g›,
  is the execution of @{term f} followed by the execution of g›.
  The function g› takes the result value \emph{and} the result
  state of f› as parameter. The definition says that the result of
  the combined operation is the result which is created
  by g› applied to the result of f›. The combined
  operation may have failed, if f› may have failed or g› may
  have failed on the result of f›.
›

text ‹
 David Sanan and Zhe Hou: The original definition of bind is very inefficient 
 when converted to executable code. Here we change it to a more efficient
 version for execution. The idea remains the same.
›

definition "h1 f s = f s"
definition "h2 g fs = (let (a,b) = fst (fs) in g a b)"
definition bind:: "('s, 'a) det_monad  ('a  ('s, 'b) det_monad)  
           ('s, 'b) det_monad" (infixl ">>=" 60)
where
"bind f g  λs. (
  let fs = h1 f s;
      v = h2 g fs
  in
  (fst v, (snd v  snd fs)))"

text ‹
  Sometimes it is convenient to write bind› in reverse order.
›
abbreviation(input)
  bind_rev :: "('c  ('a, 'b) det_monad)  ('a, 'c) det_monad  
               ('a, 'b) det_monad" (infixl "=<<" 60) where 
  "g =<< f  f >>= g"

text ‹
  The basic accessor functions of the state monad. get› returns
  the current state as result, does not fail, and does not change the state.
  put s› returns nothing (@{typ unit}), changes the current state
  to s› and does not fail.
›
definition
  get :: "('s,'s) det_monad" where
  "get  λs. ((s,s), False)"

definition
  put :: "'s  ('s, unit) det_monad" where
  "put s  λ_. (((),s), False)"

subsection "Failure"

text ‹The monad function that always fails. Returns the current 
  state and sets the failure flag.›
definition
  fail :: "'a  ('s, 'a) det_monad" where
 "fail a  λs. ((a,s), True)"

text ‹Assertions: fail if the property P› is not true›
definition
  assert :: "bool  ('a, unit) det_monad" where
 "assert P  if P then return () else fail ()"

text ‹An assertion that also can introspect the current state.›

definition
  state_assert :: "('s  bool)  ('s, unit) det_monad"
where
  "state_assert P  get >>= (λs. assert (P s))"

subsection "Generic functions on top of the state monad"

text ‹Apply a function to the current state and return the result
without changing the state.›
definition
  gets :: "('s  'a)  ('s, 'a) det_monad" where
 "gets f  get >>= (λs. return (f s))"

text ‹Modify the current state using the function passed in.›
definition
  modify :: "('s  's)  ('s, unit) det_monad" where
 "modify f  get >>= (λs. put (f s))"

lemma simpler_gets_def: "gets f = (λs. ((f s, s), False))"
  apply (simp add: gets_def return_def bind_def h1_def h2_def get_def)
  done

lemma simpler_modify_def:
  "modify f = (λs. (((), f s), False))"
  by (simp add: modify_def bind_def h1_def h2_def get_def put_def)

text ‹Execute the given monad when the condition is true, 
  return ()› otherwise.›
definition
  when1 :: "bool  ('s, unit) det_monad  
           ('s, unit) det_monad" where 
  "when1 P m  if P then m else return ()"

text ‹Execute the given monad unless the condition is true, 
  return ()› otherwise.›
definition 
  unless :: "bool  ('s, unit) det_monad  
            ('s, unit) det_monad" where
  "unless P m  when1 (¬P) m"

text ‹
  Perform a test on the current state, performing the left monad if
  the result is true or the right monad if the result is false.
›
definition
  condition :: "('s  bool)  ('s, 'r) det_monad  ('s, 'r) det_monad  ('s, 'r) det_monad"
where
  "condition P L R  λs. if (P s) then (L s) else (R s)"

notation (output)
  condition  ("(condition (_)//  (_)//  (_))" [1000,1000,1000] 1000)

subsection ‹The Monad Laws›

text ‹Each monad satisfies at least the following three laws.›

text @{term return} is absorbed at the left of a @{term bind}, 
  applying the return value directly:› 
lemma return_bind [simp]: "(return x >>= f) = f x"
  by (simp add: return_def bind_def h1_def h2_def)

text @{term return} is absorbed on the right of a @{term bind} 
lemma bind_return [simp]: "(m >>= return) = m"
  apply (rule ext)
  apply (simp add: bind_def h1_def h2_def return_def split_def)
  done
 
text @{term bind} is associative›
lemma bind_assoc: 
  fixes m :: "('a,'b) det_monad"
  fixes f :: "'b  ('a,'c) det_monad"
  fixes g :: "'c  ('a,'d) det_monad"
  shows "(m >>= f) >>= g  =  m >>= (λx. f x >>= g)"
  apply (unfold bind_def h1_def h2_def Let_def split_def)
  apply (rule ext)
  apply clarsimp
  done


section ‹Adding Exceptions›

text ‹
  The type @{typ "('s,'a) det_monad"} gives us determinism and
  failure. We now extend this monad with exceptional return values
  that abort normal execution, but can be handled explicitly.
  We use the sum type to indicate exceptions. 

  In @{typ "('s, 'e + 'a) det_monad"}, @{typ "'s"} is the state,
  @{typ 'e} is an exception, and @{typ 'a} is a normal return value.

  This new type itself forms a monad again. Since type classes in 
  Isabelle are not powerful enough to express the class of monads,
  we provide new names for the @{term return} and @{term bind} functions
  in this monad. We call them returnOk› (for normal return values)
  and bindE› (for composition). We also define throwError›
  to return an exceptional value.
›
definition
  returnOk :: "'a  ('s, 'e + 'a) det_monad" where
  "returnOk  return o Inr"

definition
  throwError :: "'e  ('s, 'e + 'a) det_monad" where
  "throwError  return o Inl"

text ‹
  Lifting a function over the exception type: if the input is an
  exception, return that exception; otherwise continue execution.
›
definition
  lift :: "('a  ('s, 'e + 'b) det_monad)  
           'e +'a  ('s, 'e + 'b) det_monad"
where
  "lift f v  case v of Inl e  throwError e
                      | Inr v'  f v'"

text ‹
  The definition of @{term bind} in the exception monad (new
  name bindE›): the same as normal @{term bind}, but 
  the right-hand side is skipped if the left-hand side
  produced an exception.
›
definition
  bindE :: "('s, 'e + 'a) det_monad  
            ('a  ('s, 'e + 'b) det_monad)  
            ('s, 'e + 'b) det_monad"  (infixl ">>=E" 60)
where
  "bindE f g  bind f (lift g)"


text ‹
  Lifting a normal deterministic monad into the 
  exception monad is achieved by always returning its
  result as normal result and never throwing an exception.
›
definition
  liftE :: "('s,'a) det_monad  ('s, 'e+'a) det_monad"
where
  "liftE f  f >>= (λr. return (Inr r))"


text ‹
  Since the underlying type and return› function changed, 
  we need new definitions for when and unless:
›
definition
  whenE :: "bool  ('s, 'e + unit) det_monad  
            ('s, 'e + unit) det_monad" 
  where
  "whenE P f  if P then f else returnOk ()"

definition
  unlessE :: "bool  ('s, 'e + unit) det_monad  
            ('s, 'e + unit) det_monad" 
  where
  "unlessE P f  if P then returnOk () else f"


text ‹
  Throwing an exception when the parameter is @{term None}, otherwise
  returning @{term "v"} for @{term "Some v"}.
›
definition
  throw_opt :: "'e  'a option  ('s, 'e + 'a) det_monad" where
  "throw_opt ex x  
  case x of None  throwError ex | Some v  returnOk v"

subsection "Monad Laws for the Exception Monad"

text ‹More direct definition of @{const liftE}:›
lemma liftE_def2:
  "liftE f = (λs. ((λ(v,s'). (Inr v, s'))  (fst (f s)), snd (f s)))"
  by (auto simp: Let_def liftE_def return_def split_def bind_def h1_def h2_def)
  
text ‹Left @{const returnOk} absorbtion over @{term bindE}:›
lemma returnOk_bindE [simp]: "(returnOk x >>=E f) = f x"
  apply (unfold bindE_def returnOk_def)
  apply (clarsimp simp: lift_def)
  done

lemma lift_return [simp]:
  "lift (return  Inr) = return"
  by (rule ext)
     (simp add: lift_def throwError_def split: sum.splits)

text ‹Right @{const returnOk} absorbtion over @{term bindE}:›
lemma bindE_returnOk [simp]: "(m >>=E returnOk) = m"
  by (simp add: bindE_def returnOk_def)

text ‹Associativity of @{const bindE}:›
lemma bindE_assoc:
  "(m >>=E f) >>=E g = m >>=E (λx. f x >>=E g)"
  apply (simp add: bindE_def bind_assoc)
  apply (rule arg_cong [where f="λx. m >>= x"])
  apply (rule ext)
  apply (case_tac x, simp_all add: lift_def throwError_def)
  done

text @{const returnOk} could also be defined via @{const liftE}:›
lemma returnOk_liftE:
  "returnOk x = liftE (return x)"
  by (simp add: liftE_def returnOk_def)

text ‹Execution after throwing an exception is skipped:›
lemma throwError_bindE [simp]:
  "(throwError E >>=E f) = throwError E"
  by (simp add: bindE_def bind_def h1_def h2_def throwError_def lift_def return_def)


section "Syntax"

text ‹This section defines traditional Haskell-like do-syntax 
  for the state monad in Isabelle.›

subsection "Syntax for the Nondeterministic State Monad"

text ‹We use K_bind› to syntactically indicate the 
  case where the return argument of the left side of a @{term bind}
  is ignored›
definition
  K_bind_def [iff]: "K_bind  λx y. x"

nonterminal
  dobinds and dobind and nobind

syntax
  "_dobind"    :: "[pttrn, 'a] => dobind"             ("(_ / _)" 10)
  ""           :: "dobind => dobinds"                 ("_")
  "_nobind"    :: "'a => dobind"                      ("_")
  "_dobinds"   :: "[dobind, dobinds] => dobinds"      ("(_);//(_)")

  "_do"        :: "[dobinds, 'a] => 'a"               ("(do ((_);//(_))//od)" 100)
translations
  "_do (_dobinds b bs) e"  == "_do b (_do bs e)"
  "_do (_nobind b) e"      == "b >>= (CONST K_bind e)"
  "do x  a; e od"        == "a >>= (λx. e)"  

text ‹Syntax examples:›
lemma "do x  return 1; 
          return (2::nat); 
          return x 
       od = 
       return 1 >>= 
       (λx. return (2::nat) >>= 
            K_bind (return x))" 
  by (rule refl)

lemma "do x  return 1; 
          return 2; 
          return x 
       od = return 1" 
  by simp

subsection "Syntax for the Exception Monad"

text ‹
  Since the exception monad is a different type, we
  need to syntactically distinguish it in the syntax.
  We use doE›/odE› for this, but can re-use
  most of the productions from do›/od›
  above.
›

syntax
  "_doE" :: "[dobinds, 'a] => 'a"  ("(doE ((_);//(_))//odE)" 100)

translations
  "_doE (_dobinds b bs) e"  == "_doE b (_doE bs e)"
  "_doE (_nobind b) e"      == "b >>=E (CONST K_bind e)"
  "doE x  a; e odE"       == "a >>=E (λx. e)"

text ‹Syntax examples:›
lemma "doE x  returnOk 1; 
           returnOk (2::nat); 
           returnOk x 
       odE =
       returnOk 1 >>=E 
       (λx. returnOk (2::nat) >>=E 
            K_bind (returnOk x))"
  by (rule refl)

lemma "doE x  returnOk 1; 
           returnOk 2; 
           returnOk x 
       odE = returnOk 1" 
  by simp



section "Library of Monadic Functions and Combinators"


text ‹Lifting a normal function into the monad type:›
definition
  liftM :: "('a  'b)  ('s,'a) det_monad  ('s, 'b) det_monad"
where
  "liftM f m  do x  m; return (f x) od"

text ‹The same for the exception monad:›
definition
  liftME :: "('a  'b)  ('s,'e+'a) det_monad  ('s,'e+'b) det_monad"
where
  "liftME f m  doE x  m; returnOk (f x) odE"

text ‹
  Run a sequence of monads from left to right, ignoring return values.›
definition
  sequence_x :: "('s, 'a) det_monad list  ('s, unit) det_monad" 
where
  "sequence_x xs  foldr (λx y. x >>= (λ_. y)) xs (return ())"

text ‹
  Map a monadic function over a list by applying it to each element
  of the list from left to right, ignoring return values.
›
definition
  mapM_x :: "('a  ('s,'b) det_monad)  'a list  ('s, unit) det_monad"
where
  "mapM_x f xs  sequence_x (map f xs)"

text ‹
  Map a monadic function with two parameters over two lists,
  going through both lists simultaneously, left to right, ignoring
  return values.
›
definition
  zipWithM_x :: "('a  'b  ('s,'c) det_monad)  
                 'a list  'b list  ('s, unit) det_monad"
where
  "zipWithM_x f xs ys  sequence_x (zipWith f xs ys)"


text ‹The same three functions as above, but returning a list of
return values instead of unit›
definition
  sequence :: "('s, 'a) det_monad list  ('s, 'a list) det_monad" 
where
  "sequence xs  let mcons = (λp q. p >>= (λx. q >>= (λy. return (x#y))))
                 in foldr mcons xs (return [])"

definition
  mapM :: "('a  ('s,'b) det_monad)  'a list  ('s, 'b list) det_monad"
where
  "mapM f xs  sequence (map f xs)"

definition
  zipWithM :: "('a  'b  ('s,'c) det_monad)  
                 'a list  'b list  ('s, 'c list) det_monad"
where
  "zipWithM f xs ys  sequence (zipWith f xs ys)"

definition
  foldM :: "('b  'a  ('s, 'a) det_monad)  'b list  'a  ('s, 'a) det_monad" 
where
  "foldM m xs a  foldr (λp q. q >>= m p) xs (return a) "

text ‹The sequence and map functions above for the exception monad,
with and without lists of return value›
definition
  sequenceE_x :: "('s, 'e+'a) det_monad list  ('s, 'e+unit) det_monad" 
where
  "sequenceE_x xs  foldr (λx y. doE _  x; y odE) xs (returnOk ())"

definition
  mapME_x :: "('a  ('s,'e+'b) det_monad)  'a list  
              ('s,'e+unit) det_monad"
where
  "mapME_x f xs  sequenceE_x (map f xs)"

definition
  sequenceE :: "('s, 'e+'a) det_monad list  ('s, 'e+'a list) det_monad" 
where
  "sequenceE xs  let mcons = (λp q. p >>=E (λx. q >>=E (λy. returnOk (x#y))))
                 in foldr mcons xs (returnOk [])"

definition
  mapME :: "('a  ('s,'e+'b) det_monad)  'a list  
              ('s,'e+'b list) det_monad"
where
  "mapME f xs  sequenceE (map f xs)"


text ‹Filtering a list using a monadic function as predicate:›
primrec
  filterM :: "('a  ('s, bool) det_monad)  'a list  ('s, 'a list) det_monad"
where
  "filterM P []       = return []"
| "filterM P (x # xs) = do
     b   P x;
     ys  filterM P xs; 
     return (if b then (x # ys) else ys)
   od"


section "Catching and Handling Exceptions"

text ‹
  Turning an exception monad into a normal state monad
  by catching and handling any potential exceptions:
›
definition
  catch :: "('s, 'e + 'a) det_monad 
            ('e  ('s, 'a) det_monad) 
            ('s, 'a) det_monad" (infix "<catch>" 10)
where
  "f <catch> handler 
     do x  f;
        case x of
          Inr b  return b
        | Inl e  handler e
     od"

text ‹
  Handling exceptions, but staying in the exception monad.
  The handler may throw a type of exceptions different from
  the left side.
›
definition
  handleE' :: "('s, 'e1 + 'a) det_monad 
               ('e1  ('s, 'e2 + 'a) det_monad) 
               ('s, 'e2 + 'a) det_monad" (infix "<handle2>" 10)
where
  "f <handle2> handler 
   do
      v  f;
      case v of
        Inl e  handler e
      | Inr v'  return (Inr v')
   od"

text ‹
  A type restriction of the above that is used more commonly in
  practice: the exception handle (potentially) throws exception
  of the same type as the left-hand side.
›
definition
  handleE :: "('s, 'x + 'a) det_monad  
              ('x  ('s, 'x + 'a) det_monad)  
              ('s, 'x + 'a) det_monad" (infix "<handle>" 10)
where
  "handleE  handleE'"


text ‹
  Handling exceptions, and additionally providing a continuation
  if the left-hand side throws no exception:
›
definition
  handle_elseE :: "('s, 'e + 'a) det_monad 
                   ('e  ('s, 'ee + 'b) det_monad) 
                   ('a  ('s, 'ee + 'b) det_monad) 
                   ('s, 'ee + 'b) det_monad"
  ("_ <handle> _ <else> _" 10)
where
  "f <handle> handler <else> continue 
   do v  f;
   case v of Inl e   handler e
           | Inr v'  continue v'
   od"

section "Hoare Logic"

subsection "Validity"

text ‹This section defines a Hoare logic for partial correctness for
  the deterministic state monad as well as the exception monad.
  The logic talks only about the behaviour part of the monad and ignores
  the failure flag.

  The logic is defined semantically. Rules work directly on the
  validity predicate.

  In the deterministic state monad, validity is a triple of precondition,
  monad, and postcondition. The precondition is a function from state to 
  bool (a state predicate), the postcondition is a function from return value
  to state to bool. A triple is valid if for all states that satisfy the
  precondition, all result values and result states that are returned by
  the monad satisfy the postcondition. Note that if the computation returns
  the empty set, the triple is trivially valid. This means @{term "assert P"} 
  does not require us to prove that @{term P} holds, but rather allows us
  to assume @{term P}! Proving non-failure is done via separate predicate and
  calculus (see below).
›
definition
  valid :: "('s  bool)  ('s,'a) det_monad  ('a  's  bool)  bool" 
  ("_/ _ /_")
where
  "P f Q  s. P s  (r s'. ((r,s') = fst (f s)  Q r s'))"

text ‹
  Validity for the exception monad is similar and build on the standard 
  validity above. Instead of one postcondition, we have two: one for
  normal and one for exceptional results.
›
definition
  validE :: "('s  bool)  ('s, 'a + 'b) det_monad  
             ('b  's  bool)  
             ('a  's  bool)  bool" 
("_/ _ /(_⦄,/ _)")
where
  "P f Q⦄,E  P f  λv s. case v of Inr r  Q r s | Inl e  E e s "


text ‹
  The following two instantiations are convenient to separate reasoning
  for exceptional and normal case.
›
definition
  validE_R :: "('s  bool)  ('s, 'e + 'a) det_monad  
               ('a  's  bool)  bool"
   ("_/ _ /_⦄, -")
where
 "P f Q⦄,-  validE P f Q (λx y. True)"

definition
  validE_E :: "('s  bool)   ('s, 'e + 'a) det_monad  
               ('e  's  bool)  bool"
   ("_/ _ /-, _")
where
 "P f -,Q  validE P f (λx y. True) Q"


text ‹Abbreviations for trivial preconditions:›
abbreviation(input)
  top :: "'a  bool" ("")
where
  "  λ_. True"

abbreviation(input)
  bottom :: "'a  bool" ("")
where
  "  λ_. False"

text ‹Abbreviations for trivial postconditions (taking two arguments):›
abbreviation(input)
  toptop :: "'a  'b  bool" ("⊤⊤")
where
 "⊤⊤  λ_ _. True"

abbreviation(input)
  botbot :: "'a  'b  bool" ("⊥⊥")
where
 "⊥⊥  λ_ _. False"

text ‹
  Lifting ∧› and ∨› over two arguments. 
  Lifting ∧› and ∨› over one argument is already
  defined (written and› and or›).
›
definition
  bipred_conj :: "('a  'b  bool)  ('a  'b  bool)  ('a  'b  bool)" 
  (infixl "And" 96)
where
  "bipred_conj P Q  λx y. P x y  Q x y"

definition
  bipred_disj :: "('a  'b  bool)  ('a  'b  bool)  ('a  'b  bool)" 
  (infixl "Or" 91)
where
  "bipred_disj P Q  λx y. P x y  Q x y"


subsection "Determinism"

text ‹A monad of type det_monad› is deterministic iff it
returns exactly one state and result and does not fail› 
definition
  det :: "('a,'s) det_monad  bool"
where
  "det f  s. r. f s = (r,False)" 

text ‹A deterministic det_monad› can be turned
  into a normal state monad:›
definition
  the_run_state :: "('s,'a) det_monad  's  'a × 's"
where
  "the_run_state M  λs. THE s'. fst (M s) = s'"


subsection "Non-Failure"

text ‹
  With the failure flag, we can formulate non-failure separately
  from validity. A monad m› does not fail under precondition
  P›, if for no start state in that precondition it sets
  the failure flag.
›
definition
  no_fail :: "('s  bool)  ('s,'a) det_monad  bool"
where
  "no_fail P m  s. P s  ¬ (snd (m s))"


text ‹
  It is often desired to prove non-failure and a Hoare triple
  simultaneously, as the reasoning is often similar. The following
  definitions allow such reasoning to take place.
›

definition
  validNF ::"('s  bool)  ('s,'a) det_monad  ('a  's  bool)  bool"
      ("_/ _ /_⦄!")
where
  "validNF P f Q  valid P f Q  no_fail P f"

definition
  validE_NF :: "('s  bool)  ('s, 'a + 'b) det_monad 
             ('b  's  bool) 
             ('a  's  bool)  bool"
  ("_/ _ /(_⦄,/ _⦄!)")
where
  "validE_NF P f Q E  validE P f Q E  no_fail P f"

lemma validE_NF_alt_def:
  " P  B  Q ⦄, E ⦄! =  P  B  λv s. case v of Inl e  E e s | Inr r  Q r s ⦄!"
  by (clarsimp simp: validE_NF_def validE_def validNF_def)

section "Basic exception reasoning"

text ‹
  The following predicates no_throw› and no_return› allow
  reasoning that functions in the exception monad either do
  no throw an exception or never return normally.
›

definition "no_throw P A   P  A  λ_ _. True ⦄, λ_ _. False "

definition "no_return P A   P  A λ_ _. False⦄,λ_ _. True "

end

Theory DetMonadLemmas

(*
 * Copyright 2014, NICTA
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * @TAG(NICTA_BSD)
 *)

(* Zhe Hou: I removed the lemmas related to the definitions which are 
*  removed from DetMonad. That is, only those lemmas for deterministic
*  monads are kept here. 
*)

theory DetMonadLemmas
imports DetMonad
begin

section "General Lemmas Regarding the Deterministic State Monad"

subsection "Congruence Rules for the Function Package"

lemma bind_cong[fundef_cong]:
  " f = f'; v s s'. (v, s') = fst (f' s)  g v s' = g' v s'   f >>= g = f' >>= g'"
  apply (rule ext) 
  apply (auto simp: bind_def h1_def h2_def Let_def split_def intro: rev_image_eqI)
  done

lemma bind_apply_cong [fundef_cong]:
  " f s = f' s'; rv st. (rv, st) = fst (f' s')  g rv st = g' rv st 
        (f >>= g) s = (f' >>= g') s'"
  apply (simp add: bind_def h1_def h2_def)
  apply (auto simp: split_def intro: SUP_cong [OF refl] intro: rev_image_eqI)
  done

lemma bindE_cong[fundef_cong]:
  " M = M' ; v s s'. (Inr v, s') = fst (M' s)  N v s' = N' v s'   bindE M N = bindE M' N'"
  apply (simp add: bindE_def)
  apply (rule bind_cong)
   apply (rule refl)
  apply (unfold lift_def)
  apply (case_tac v, simp_all)
  done

lemma bindE_apply_cong[fundef_cong]:
  " f s = f' s'; rv st. (Inr rv, st) = fst (f' s')  g rv st = g' rv st  
   (f >>=E g) s = (f' >>=E g') s'"
  apply (simp add: bindE_def)
  apply (rule bind_apply_cong)
   apply assumption
  apply (case_tac rv, simp_all add: lift_def)
  done

lemma K_bind_apply_cong[fundef_cong]:
  " f st = f' st'   K_bind f arg st = K_bind f' arg' st'"
  by simp

lemma when_apply_cong[fundef_cong]:
  " C = C'; s = s'; C'  m s' = m' s'   whenE C m s = whenE C' m' s'"
  by (simp add: whenE_def)

lemma unless_apply_cong[fundef_cong]:
  " C = C'; s = s'; ¬ C'  m s' = m' s'   unlessE C m s = unlessE C' m' s'"
  by (simp add: unlessE_def)

lemma whenE_apply_cong[fundef_cong]:
  " C = C'; s = s'; C'  m s' = m' s'   whenE C m s = whenE C' m' s'"
  by (simp add: whenE_def)

lemma unlessE_apply_cong[fundef_cong]:
  " C = C'; s = s'; ¬ C'  m s' = m' s'   unlessE C m s = unlessE C' m' s'"
  by (simp add: unlessE_def)

subsection "Simplifying Monads"

lemma nested_bind [simp]:
  "do x  do y  f; return (g y) od; h x od =
   do y  f; h (g y) od"
  apply (clarsimp simp add: bind_def h1_def h2_def)
  apply (rule ext)
  apply (clarsimp simp add: Let_def split_def return_def)
  done

lemma assert_True [simp]:
  "assert True >>= f = f ()"
  by (simp add: assert_def)

lemma when_True_bind [simp]:
  "when1 True g >>= f = g >>= f"
  by (simp add: when1_def bind_def return_def)

lemma whenE_False_bind [simp]:
  "whenE False g >>=E f = f ()"
  by (simp add: whenE_def bindE_def returnOk_def lift_def)

lemma whenE_True_bind [simp]:
  "whenE True g >>=E f = g >>=E f"
  by (simp add: whenE_def bindE_def returnOk_def lift_def)

lemma when_True [simp]: "when1 True X = X"
  by (clarsimp simp: when1_def)

lemma when_False [simp]: "when1 False X = return ()"
  by (clarsimp simp: when1_def)

lemma unless_False [simp]: "unless False X = X"
  by (clarsimp simp: unless_def)

lemma unless_True [simp]: "unless True X = return ()"
  by (clarsimp simp: unless_def)

lemma unlessE_whenE:
  "unlessE P = whenE (~P)"
  by (rule ext)+ (simp add: unlessE_def whenE_def)

lemma unless_when:
  "unless P = when1 (~P)"
  by (rule ext)+ (simp add: unless_def when1_def)

lemma gets_to_return [simp]: "gets (λs. v) = return v"
  by (clarsimp simp: gets_def put_def get_def bind_def h1_def h2_def return_def)

lemma liftE_handleE' [simp]: "((liftE a) <handle2> b) = liftE a"
  apply (clarsimp simp: liftE_def handleE'_def)
  done

lemma liftE_handleE [simp]: "((liftE a) <handle> b) = liftE a"
  apply (unfold handleE_def)
  apply simp
  done

lemma condition_split:
  "P (condition C a b s) = ((((C s)  P (a s))  (¬ (C s)  P (b s))))"
  apply (clarsimp simp: condition_def)
  done

lemma condition_split_asm:
  "P (condition C a b s) = (¬ (C s  ¬ P (a s)  ¬ C s  ¬ P (b s)))"
  apply (clarsimp simp: condition_def)
  done

lemmas condition_splits = condition_split condition_split_asm

lemma condition_true_triv [simp]:
  "condition (λ_. True) A B = A"
  apply (rule ext)
  apply (clarsimp split: condition_splits)
  done

lemma condition_false_triv [simp]:
  "condition (λ_. False) A B = B"
  apply (rule ext)
  apply (clarsimp split: condition_splits)
  done

lemma condition_true: " P s   condition P A B s = A s"
  apply (clarsimp simp: condition_def)
  done

lemma condition_false: " ¬ P s   condition P A B s = B s"
  apply (clarsimp simp: condition_def)
  done

section "Low-level monadic reasoning"

lemma valid_make_schematic_post:
  "(s0.  λs. P s0 s  f  λrv s. Q s0 rv s ) 
    λs. s0. P s0 s  (rv s'. Q s0 rv s'  Q' rv s')  f  Q' "
  by (auto simp add: valid_def no_fail_def split: prod.splits)

lemma validNF_make_schematic_post:
  "(s0.  λs. P s0 s  f  λrv s. Q s0 rv s ⦄!) 
    λs. s0. P s0 s  (rv s'. Q s0 rv s'  Q' rv s')  f  Q' ⦄!"
  by (auto simp add: valid_def validNF_def no_fail_def split: prod.splits)

lemma validE_make_schematic_post:
  "(s0.  λs. P s0 s  f  λrv s. Q s0 rv s ⦄,  λrv s. E s0 rv s ) 
    λs. s0. P s0 s  (rv s'. Q s0 rv s'  Q' rv s')
         (rv s'. E s0 rv s'  E' rv s')  f  Q' ⦄,  E' "
  by (auto simp add: validE_def valid_def no_fail_def split: prod.splits sum.splits)

lemma validE_NF_make_schematic_post:
  "(s0.  λs. P s0 s  f  λrv s. Q s0 rv s ⦄,  λrv s. E s0 rv s ⦄!) 
    λs. s0. P s0 s  (rv s'. Q s0 rv s'  Q' rv s')
         (rv s'. E s0 rv s'  E' rv s')  f  Q' ⦄,  E' ⦄!"
  by (auto simp add: validE_NF_def validE_def valid_def no_fail_def split: prod.splits sum.splits)

lemma validNF_conjD1: " P  f  λrv s. Q rv s  Q' rv s ⦄!   P  f  Q ⦄!"
  by (fastforce simp: validNF_def valid_def no_fail_def)

lemma validNF_conjD2: " P  f  λrv s. Q rv s  Q' rv s ⦄!   P  f  Q' ⦄!"
  by (fastforce simp: validNF_def valid_def no_fail_def)

lemma exec_gets:
  "(gets f >>= m) s = m (f s) s"
  by (simp add: simpler_gets_def bind_def h1_def h2_def)

lemma in_gets:
  "(r, s') = fst (gets f s) = (r = f s  s' = s)"
  by (simp add: simpler_gets_def)

end

Theory RegistersOps

section‹Register Operations›
theory RegistersOps
imports Main "../lib/WordDecl" "Word_Lib.Traditional_Infix_Syntax"
begin

text‹
 This theory provides operations to get, set and clear bits in registers
›

section "Getting Fields"
  
text‹
  Get a field of type @{typ "'b::len word"} 
  starting at @{term "index"} from @{term "addr"} of type @{typ "'a::len word"}
definition get_field_from_word_a_b:: "'a::len word  nat  'b::len word"
 where
  "get_field_from_word_a_b addr index 
     let off = (size addr - LENGTH('b)) 
       in ucast ((addr << (off-index)) >> off)"

text‹
  Obtain, from addr of type @{typ "'a::len word"}, 
  another @{typ "'a::len word"} containing the field of length len›
  starting at index› in addr›. 
›
definition get_field_from_word_a_a:: "'a::len word  nat  nat  'a::len word"
 where
  "get_field_from_word_a_a addr index len 
     (addr << (size addr - (index+len)) >> (size addr - len))"

section "Setting Fields"

text‹
  Set the field of type @{typ "'b::len word"} 
  at index› from record›
  of type @{typ "'a::len word"}. 
›
definition set_field :: "'a::len word  'b::len word  nat  'a::len word"
 where 
  "set_field record field index 
     let mask:: ('a::len word) = (mask (size field)) << index 
      in  (record AND (NOT mask)) OR ((ucast field) << index)"


section "Clearing Fields"

text‹
  Zero the n› initial bits of addr›.
›
definition clear_n_bits:: "'a::len word  nat  'a::len word" 
 where
   "clear_n_bits addr n  addr AND (NOT (mask n))"

text‹
  Gets the natural value of a 32 bit mask 
›

definition get_nat_from_mask::"word32  nat  nat  (word32 × nat)" 
where
"
get_nat_from_mask w m v  if (w AND (mask m) =0) then (w>>m, v+m)
                          else (w,m)
"

definition get_nat_from_mask32::"word32 nat"
where
"get_nat_from_mask32 w  
                            if (w=0) then len_of TYPE (word_length32)
                            else
                                let (w,res) = get_nat_from_mask w 16 0 in
                                     let (w,res)= get_nat_from_mask w 8 res in
                                          let (w,res) = get_nat_from_mask w 4 res in
                                              let (w,res) = get_nat_from_mask w 2 res in
                                                  let (w,res) = get_nat_from_mask w 1 res in
                                                        res
"

end 

Theory MMU

(*  Title:     Memory.thy
    Author:    David Sanán, Trinity College Dublin, 2012
               Zhe Hou, NTU, 2016.
*)


section ‹Memory Management Unit (MMU)›

theory MMU
imports Main RegistersOps Sparc_Types
begin

section ‹MMU  Sizing› 

text‹
  We need some citation here for documentation about the MMU.
›
text‹The MMU uses the Address Space Identifiers (ASI) to control memory access.
ASI = 8, 10 are for user; ASI = 9, 11 are for supervisor.›

subsection "MMU Types"

type_synonym word_PTE_flags = word8
type_synonym word_length_PTE_flags = word_length8

subsection "MMU length values"

text‹Definitions for the length of the virtua address, page size,  
virtual translation tables indexes, virtual address offset and Page protection flags›


definition length_entry_type :: "nat" 
where "length_entry_type  LENGTH(word_length_entry_type)" 
definition length_phys_address:: "nat" 
where "length_phys_address  LENGTH(word_length_phys_address)"
definition length_virtua_address:: "nat" 
where "length_virtua_address  LENGTH(word_length_virtua_address)"
definition length_page:: "nat" where "length_page  LENGTH(word_length_page)"
definition length_t1:: "nat" where "length_t1  LENGTH(word_length_t1)"
definition length_t2:: "nat" where "length_t2  LENGTH(word_length_t2)"
definition length_t3:: "nat" where "length_t3  LENGTH(word_length_t3)"
definition length_offset:: "nat" where "length_offset  LENGTH(word_length_offset)"
definition length_PTE_flags :: "nat" where 
"length_PTE_flags  LENGTH(word_length_PTE_flags)"

subsection "MMU index values"

definition va_t1_index :: "nat" where "va_t1_index  length_virtua_address - length_t1"
definition va_t2_index :: "nat" where "va_t2_index  va_t1_index - length_t2"
definition va_t3_index :: "nat" where "va_t3_index  va_t2_index - length_t3"
definition va_offset_index :: "nat" where "va_offset_index  va_t3_index - length_offset"
definition pa_page_index :: "nat" 
where "pa_page_index  length_phys_address - length_page"
definition pa_offset_index :: "nat" where 
"pa_offset_index  pa_page_index -length_page"

section ‹MMU Definition›

record MMU_state =
   registers :: "MMU_context"
(*   contexts:: context_table*)

text ‹The following functions access MMU registers via addresses. 
  See UT699LEON3FT manual page 35.›

definition mmu_reg_val:: "MMU_state  virtua_address  machine_word option"
where "mmu_reg_val mmu_state addr 
  if addr = 0x000 then ― ‹MMU control register›
    Some ((registers mmu_state) CR)
  else if addr = 0x100 then ― ‹Context pointer register›
    Some ((registers mmu_state) CTP)
  else if addr = 0x200 then ― ‹Context register›
    Some ((registers mmu_state) CNR)
  else if addr = 0x300 then ― ‹Fault status register›
    Some ((registers mmu_state) FTSR)
  else if addr = 0x400 then ― ‹Fault address register›
    Some ((registers mmu_state) FAR)
  else None"

definition mmu_reg_mod:: "MMU_state  virtua_address  machine_word 
  MMU_state option" where
"mmu_reg_mod mmu_state addr w 
  if addr = 0x000 then ― ‹MMU control register›
    Some (mmu_stateregisters := (registers mmu_state)(CR := w))
  else if addr = 0x100 then ― ‹Context pointer register›
    Some (mmu_stateregisters := (registers mmu_state)(CTP := w))
  else if addr = 0x200 then ― ‹Context register›
    Some (mmu_stateregisters := (registers mmu_state)(CNR := w))
  else if addr = 0x300 then ― ‹Fault status register›
    Some (mmu_stateregisters := (registers mmu_state)(FTSR := w))
  else if addr = 0x400 then ― ‹Fault address register›
    Some (mmu_stateregisters := (registers mmu_state)(FAR := w))
  else None"

section ‹Virtual Memory›

subsection ‹MMU Auxiliary Definitions›

definition getCTPVal:: "MMU_state  machine_word"
where "getCTPVal mmu   (registers mmu) CTP"

definition getCNRVal::"MMU_state  machine_word"
where "getCNRVal mmu   (registers mmu) CNR"


text‹
 The physical context table address is got from the ConText Pointer register (CTP) and the 
Context Register (CNR) MMU registers. 
 The CTP is shifted to align it with 
the physical address (36 bits) and we add the table index given on CNR.
CTP is right shifted 2 bits, cast to phys address and left shifted 6 bytes 
to be aligned with the context register.  
CNR is 2 bits left shifted for alignment with the context table.
›

definition compose_context_table_addr :: "machine_word machine_word 
                                           phys_address"
where 
 "compose_context_table_addr ctp cnr 
     ((ucast (ctp >> 2)) << 6) + (ucast cnr << 2)"

subsection ‹Virtual Address Translation›

text‹Get the context table phys address from the MMU registers›
definition get_context_table_addr :: "MMU_state  phys_address"
where 
 "get_context_table_addr mmu 
      compose_context_table_addr (getCTPVal mmu) (getCNRVal mmu)"

definition va_list_index :: "nat list" where
"va_list_index  [va_t1_index,va_t2_index,va_t3_index,0]"

definition offset_index :: "nat list" where
"offset_index 
   [ length_machine_word
    , length_machine_word-length_t1
    , length_machine_word-length_t1-length_t2
    , length_machine_word-length_t1-length_t2-length_t3
    ]"

definition index_len_table :: "nat list" where "index_len_table  [8,6,6,0]"

definition n_context_tables :: "nat" where "n_context_tables  3"

text ‹The following are basic physical memory read functions. 
At this level we don't need the write memory yet.›

definition mem_context_val:: "asi_type  phys_address  
                      mem_context  mem_val_type option"
where
"mem_context_val asi add m  
  let asi8 = word_of_int 8;
      r1 = m asi add 
  in
  if r1 = None then
    m asi8 add
  else r1
"

text ‹Given an ASI (word8), an address (word32) addr, 
        read the 32bit value from the memory addresses 
        starting from address addr' where addr' = addr 
        exception that the last two bits are 0's. 
        That is, read the data from 
        addr', addr'+1, addr'+2, addr'+3.›
definition mem_context_val_w32 :: "asi_type  phys_address  
                           mem_context  word32 option"
where
"mem_context_val_w32 asi addr m 
  let addr' = (AND) addr 0b111111111111111111111111111111111100;
      addr0 = (OR) addr' 0b000000000000000000000000000000000000;
      addr1 = (OR) addr' 0b000000000000000000000000000000000001;
      addr2 = (OR) addr' 0b000000000000000000000000000000000010;
      addr3 = (OR) addr' 0b000000000000000000000000000000000011;
      r0 = mem_context_val asi addr0 m;
      r1 = mem_context_val asi addr1 m;
      r2 = mem_context_val asi addr2 m;
      r3 = mem_context_val asi addr3 m
  in
  if r0 = None  r1 = None  r2 = None  r3 = None then
    None
  else
    let byte0 = case r0 of Some v  v;
        byte1 = case r1 of Some v  v;
        byte2 = case r2 of Some v  v;
        byte3 = case r3 of Some v  v 
    in
    Some ((OR) ((OR) ((OR) ((ucast(byte0)) << 24) 
                              ((ucast(byte1)) << 16)) 
                       ((ucast(byte2)) << 8)) 
                (ucast(byte3)))
"

text @{term "get_addr_from_table"} browses the page description tables  
  until it finds a PTE (bits==suc (suc 0).

  If it is a PTE it aligns the 24 most significant bits of the entry
  with the most significant bits of the phys address and or-ed with the offset,
   which will vary depending on the entry level. 
 In the case we are looking at the last table level (level 3),
   the offset is aligned to 0 otherwise it will be 2.
  
 If the table entry is a PTD (bits== Suc 0),
  the index is obtained from the virtual address depending on the current level and or-ed with the PTD. 
›

function ptd_lookup:: "virtua_address  virtua_address 
mem_context  nat  (phys_address × PTE_flags) option" 
where "ptd_lookup va pt m lvl = (
  if lvl > 3 then None
  else 
    let thislvl_offset = (
      if lvl = 1 then (ucast ((ucast (va >> 24))::word8))::word32
      else if lvl = 2 then (ucast ((ucast (va >> 18))::word6))::word32
      else (ucast ((ucast (va >> 12))::word6))::word32);
        thislvl_addr = (OR) pt thislvl_offset;
        thislvl_data = mem_context_val_w32 (word_of_int 9) (ucast thislvl_addr) m
    in
    case thislvl_data of 
    Some v  (
      let et_val = (AND) v 0b00000000000000000000000000000011 in
      if et_val = 0 then ― ‹Invalid›
        None
      else if et_val = 1 then ― ‹Page Table Descriptor›
        let ptp = (AND) v 0b11111111111111111111111111111100 in
        ptd_lookup va ptp m (lvl+1)
      else if et_val = 2 then ― ‹Page Table Entry›
        let ppn = (ucast (v >> 8))::word24;
            va_offset = (ucast ((ucast va)::word12))::word36
        in
        Some (((OR) (((ucast ppn)::word36) << 12) va_offset), 
              ((ucast v)::word8))
      else ― ‹et_val = 3›, reserved.›
        None
    )
    |None  None)
"
by pat_completeness auto
termination  
by (relation "measure (λ (va, (pt, (m, lvl))). 4 - lvl)") auto

definition get_acc_flag:: "PTE_flags  word3" where
"get_acc_flag w8  (ucast (w8 >> 2))::word3"

definition mmu_readable:: "word3  asi_type  bool" where
"mmu_readable f asi 
  if uint asi  {8, 10} then
    if uint f  {0,1,2,3,5} then True
    else False
  else if uint asi  {9, 11} then
    if uint f  {0,1,2,3,5,6,7} then True
    else False
  else False
"

definition mmu_writable:: "word3  asi_type  bool" where
"mmu_writable f asi 
  if uint asi  {8, 10} then
    if uint f  {1,3} then True
    else False
  else if uint asi  {9, 11} then
    if uint f  {1,3,5,7} then True
    else False
  else False
"

definition virt_to_phys :: "virtua_address  MMU_state   mem_context  
                            (phys_address × PTE_flags) option"
where 
 "virt_to_phys va mmu m  
    let ctp_val = mmu_reg_val mmu (0x100);
        cnr_val = mmu_reg_val mmu (0x200);
        mmu_cr_val = (registers mmu) CR
    in
    if (AND) mmu_cr_val 1  0 then ― ‹MMU enabled.›
      case (ctp_val,cnr_val) of
      (Some v1, Some v2) 
        let context_table_entry = (OR) ((v1 >> 11) << 11)
            (((AND) v2 0b00000000000000000000000111111111) << 2);
            context_table_data = mem_context_val_w32 (word_of_int 9) 
              (ucast context_table_entry) m
        in (
        case context_table_data of
        Some lvl1_page_table 
          ptd_lookup va lvl1_page_table m 1
        |None  None)
      |_  None
    else Some ((ucast va), ((0b11101111)::word8)) 
"

text ‹
\newpage

The below function gives the initial values of MMU registers.
In particular, the MMU context register CR is 0 because:
We don't know the bits for IMPL, VER, and SC;
the bits for PSO are 0s because we use TSO;
the reserved bits are 0s;
we assume NF bits are 0s;
and most importantly, the E bit is 0 because when the machine 
starts up, MMU is disabled. 
An initial boot procedure (bootloader or something like that) should 
configure the MMU and then enable it if the OS uses MMU.›

definition MMU_registers_init :: "MMU_context"
where "MMU_registers_init r  0" 

definition mmu_setup :: "MMU_state"
where "mmu_setup  registers=MMU_registers_init"

end

Theory Sparc_State

(*
 * Copyright 2016, NTU
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * Author: Zhe Hou, David Sanan.
 *)

section ‹SPARC V8 state model›
theory Sparc_State
imports Main Sparc_Types  "../lib/wp/DetMonadLemmas" MMU
begin                                                                    
section ‹state as a function›

record cpu_cache = 
dcache:: cache_context
icache:: cache_context

text‹
The state @{term sparc_state} is defined as a tuple @{term cpu_context}, 
@{term user_context}, @{term mem_context}, defining the state of the CPU registers, 
user registers, memory, cache, and delayed write pool respectively. 
Additionally, a boolean indicates whether the state is 
undefined or not.
›

record (overloaded) ('a) sparc_state =
cpu_reg:: cpu_context
user_reg:: "('a) user_context"
sys_reg:: sys_context
mem:: mem_context
mmu:: MMU_state
cache:: cpu_cache
dwrite:: delayed_write_pool
state_var:: sparc_state_var
traps:: "Trap set"
undef:: bool

section‹functions for state member access›

definition cpu_reg_val:: "CPU_register  ('a) sparc_state  reg_type"
where
"cpu_reg_val reg state  (cpu_reg state) reg"

definition cpu_reg_mod :: "word32  CPU_register  ('a) sparc_state  
                           ('a) sparc_state"
where "cpu_reg_mod data_w32 cpu state  
  statecpu_reg := ((cpu_reg state)(cpu := data_w32))"

text ‹r[0] = 0. Otherwise read the actual value.›
definition user_reg_val:: "('a) window_size  user_reg_type  ('a) sparc_state  reg_type"
where
"user_reg_val window ur state  
  if ur = 0 then 0
  else (user_reg state) window ur"

text ‹Write a global register. win should be initialised as NWINDOWS.›
fun (sequential) global_reg_mod :: "word32  nat  user_reg_type  
  ('a::len) sparc_state  ('a) sparc_state"
where
"global_reg_mod data_w32 0 ur state = state"
|
"global_reg_mod data_w32 win ur state = (
    let win_word = word_of_int (int (win-1));
        ns = stateuser_reg := 
          (user_reg state)(win_word := ((user_reg state) win_word)(ur := data_w32)) 
    in
    global_reg_mod data_w32 (win-1) ur ns
)"

text ‹Compute the next window.›
definition next_window :: "('a::len) window_size  ('a) window_size"
where
"next_window win 
  if (uint win) < (NWINDOWS - 1) then (win + 1)
  else 0
"

text ‹Compute the previous window.›
definition pre_window :: "('a::len) window_size  ('a::len) window_size"
where
"pre_window win 
  if (uint win) > 0 then (win - 1)
  else (word_of_int (NWINDOWS - 1))
"

text ‹write an output register. 
  Also write ur+16 of the previous window.›
definition out_reg_mod :: "word32  ('a::len) window_size  user_reg_type  
  ('a) sparc_state  ('a) sparc_state"
where
"out_reg_mod data_w32 win ur state 
  let state' = stateuser_reg :=
        (user_reg state)(win := ((user_reg state) win)(ur := data_w32));
      win' = pre_window win;
      ur' = ur + 16
  in
  state'user_reg := 
    (user_reg state')(win' := ((user_reg state') win')(ur' := data_w32))
"

text ‹Write a input register.
  Also write ur-16 of the next window.›
definition in_reg_mod :: "word32  ('a::len) window_size  user_reg_type 
  ('a) sparc_state  ('a) sparc_state"
where
"in_reg_mod data_w32 win ur state 
  let state' = stateuser_reg :=
    (user_reg state)(win := ((user_reg state) win)(ur := data_w32));
      win' = next_window win;
      ur' = ur - 16
  in
  state'user_reg :=
    (user_reg state')(win' := ((user_reg state') win')(ur' := data_w32))
"

text ‹Do not modify r[0].›
definition user_reg_mod :: "word32  ('a::len) window_size  user_reg_type  
 ('a) sparc_state  ('a) sparc_state"
where
"user_reg_mod data_w32 win ur state 
  if ur = 0 then state
  else if 0 < ur  ur < 8 then
    global_reg_mod data_w32 (nat NWINDOWS) ur state
  else if 7 < ur  ur < 16 then 
    out_reg_mod data_w32 win ur state
  else if 15 < ur  ur < 24 then
    stateuser_reg := 
      (user_reg state)(win := ((user_reg state) win)(ur := data_w32))
  else ⌦‹if 23 < ur ∧ ur < 32 then›
    in_reg_mod data_w32 win ur state
  ⌦‹else state›
"

definition sys_reg_val :: "sys_reg  ('a) sparc_state  reg_type"
where
"sys_reg_val reg state  (sys_reg state) reg"

definition sys_reg_mod :: "word32  sys_reg  
                          ('a) sparc_state  ('a) sparc_state"
where
"sys_reg_mod data_w32 sys state  statesys_reg := (sys_reg state)(sys := data_w32)"

text ‹The following fucntions deal with physical memory. 
N.B. Physical memory address in SPARCv8 is 36-bit.›

text ‹LEON3 doesn't distinguish ASI 8 and 9; 10 and 11 for read access
  for both user and supervisor. 
We recently discovered that the compiled machine code by
the sparc-elf compiler often reads asi = 10 (user data) 
when the actual content is store in asi = 8 (user instruction).
For testing purposes, we don't distinguish asi = 8,9,10,11
for reading access.›

definition mem_val:: "asi_type  phys_address  
                      ('a) sparc_state  mem_val_type option"
where
"mem_val asi add state  
  let asi8 = word_of_int 8;
      asi9 = word_of_int 9;
      asi10 = word_of_int 10;
      asi11 = word_of_int 11;
      r1 = (mem state) asi8 add
  in
  if r1 = None then
    let r2 = (mem state) asi9 add in
    if r2 = None then
      let r3 = (mem state) asi10 add in
      if r3 = None then 
        (mem state) asi11 add
      else r3
    else r2
  else r1
"

text ‹An alternative way to read values from memory. 
Some implementations may use this definition.›

definition mem_val_alt:: "asi_type  phys_address  
                      ('a) sparc_state  mem_val_type option"
where
"mem_val_alt asi add state  
  let r1 = (mem state) asi add; 
      asi8 = word_of_int 8;
      asi9 = word_of_int 9;
      asi10 = word_of_int 10;
      asi11 = word_of_int 11
  in
  if r1 = None  (uint asi) = 8 then
    let r2 = (mem state) asi9 add in
    r2
  else if r1 = None  (uint asi) = 9 then
    let r2 = (mem state) asi8 add in
    r2
  else if r1 = None  (uint asi) = 10 then
    let r2 = (mem state) asi11 add in
    if r2 = None then
      let r3 = (mem state) asi8 add in
      if r3 = None then
        (mem state) asi9 add        
      else r3
    else r2
  else if r1 = None  (uint asi) = 11 then
    let r2 = (mem state) asi10 add in
    if r2 = None then
      let r3 = (mem state) asi8 add in
      if r3 = None then
        (mem state) asi9 add        
      else r3
    else r2
  else r1"

definition mem_mod :: "asi_type  phys_address  mem_val_type  
                         ('a) sparc_state  ('a) sparc_state"
where
"mem_mod asi addr val state 
  let state1 = statemem := (mem state)
    (asi := ((mem state) asi)(addr := Some val))
  in ― ‹Only allow one of asi› 8 and 9 (10 and 11) to have value.›
  if (uint asi) = 8  (uint asi) = 10 then
    let asi2 = word_of_int ((uint asi) + 1) in
    state1mem := (mem state1)
      (asi2 := ((mem state1) asi2)(addr := None))
  else if (uint asi) = 9  (uint asi) = 11 then
    let asi2 = word_of_int ((uint asi) - 1) in
    state1mem := (mem state1)(asi2 := ((mem state1) asi2)(addr := None))
  else state1
"

text ‹An alternative way to write memory. This method insists that 
for each address, it can only hold a value in one of ASI = 8,9,10,11.›

definition mem_mod_alt :: "asi_type  phys_address  mem_val_type  
                         ('a) sparc_state  ('a) sparc_state"
where
"mem_mod_alt asi addr val state 
  let state1 = statemem := (mem state)
    (asi := ((mem state) asi)(addr := Some val));
    asi8 = word_of_int 8;
    asi9 = word_of_int 9;
    asi10 = word_of_int 10;
    asi11 = word_of_int 11
  in 
  ― ‹Only allow one of asi› 8, 9, 10, 11 to have value.›
  if (uint asi) = 8 then 
    let state2 = state1mem := (mem state1)
      (asi9 := ((mem state1) asi9)(addr := None));
     state3 = state2mem := (mem state2)
      (asi10 := ((mem state2) asi10)(addr := None));
     state4 = state3mem := (mem state3)
      (asi11 := ((mem state3) asi11)(addr := None))
    in
    state4
  else if (uint asi) = 9 then 
    let state2 = state1mem := (mem state1)
      (asi8 := ((mem state1) asi8)(addr := None));  
     state3 = state2mem := (mem state2)
      (asi10 := ((mem state2) asi10)(addr := None));
     state4 = state3mem := (mem state3)
      (asi11 := ((mem state3) asi11)(addr := None))
    in
    state4  
  else if (uint asi) = 10 then 
    let state2 = state1mem := (mem state1)
      (asi9 := ((mem state1) asi9)(addr := None));
     state3 = state2mem := (mem state2)
      (asi8 := ((mem state2) asi8)(addr := None));
     state4 = state3mem := (mem state3)
      (asi11 := ((mem state3) asi11)(addr := None))
    in
    state4
  else if (uint asi) = 11 then 
    let state2 = state1mem := (mem state1)
      (asi9 := ((mem state1) asi9)(addr := None));
     state3 = state2mem := (mem state2)
      (asi10 := ((mem state2) asi10)(addr := None));
     state4 = state3mem := (mem state3)
      (asi8 := ((mem state3) asi8)(addr := None))
    in
    state4
  else state1
"

text ‹Given an ASI (word8), an address (word32) addr, 
        read the 32bit value from the memory addresses 
        starting from address addr' where addr' = addr 
        exception that the last two bits are 0's. 
        That is, read the data from 
        addr', addr'+1, addr'+2, addr'+3.›
definition mem_val_w32 :: "asi_type  phys_address  
                           ('a) sparc_state  word32 option"
where
"mem_val_w32 asi addr state 
  let addr' = (AND) addr 0b111111111111111111111111111111111100;
      addr0 = addr';
      addr1 = addr' + 1;
      addr2 = addr' + 2;
      addr3 = addr' + 3;
      r0 = mem_val_alt asi addr0 state;
      r1 = mem_val_alt asi addr1 state;
      r2 = mem_val_alt asi addr2 state;
      r3 = mem_val_alt asi addr3 state
  in
  if r0 = None  r1 = None  r2 = None  r3 = None then
    None
  else
    let byte0 = case r0 of Some v  v;
        byte1 = case r1 of Some v  v;
        byte2 = case r2 of Some v  v;
        byte3 = case r3 of Some v  v 
    in
    Some ((OR) ((OR) ((OR) ((ucast(byte0)) << 24) 
                              ((ucast(byte1)) << 16)) 
                       ((ucast(byte2)) << 8)) 
                (ucast(byte3)))
"

text ‹
  Let addr'› be addr› with last two bits set to 0's.
  Write the 32bit data in the memory address addr'›
  (and the following 3 addresses). 
  byte_mask› decides which byte of the 32bits are written.
›
definition mem_mod_w32 :: "asi_type  phys_address  word4  word32  
                           ('a) sparc_state  ('a) sparc_state"
where
"mem_mod_w32 asi addr byte_mask data_w32 state 
  let addr' = (AND) addr 0b111111111111111111111111111111111100;
      addr0 = (OR) addr' 0b000000000000000000000000000000000000;
      addr1 = (OR) addr' 0b000000000000000000000000000000000001;
      addr2 = (OR) addr' 0b000000000000000000000000000000000010;
      addr3 = (OR) addr' 0b000000000000000000000000000000000011;
      byte0 = (ucast (data_w32 >> 24))::mem_val_type;
      byte1 = (ucast (data_w32 >> 16))::mem_val_type;
      byte2 = (ucast (data_w32 >> 8))::mem_val_type;
      byte3 = (ucast data_w32)::mem_val_type;
      s0 = if (((AND) byte_mask (0b1000::word4)) >> 3) = 1 then
              mem_mod asi addr0 byte0 state 
           else state;
      s1 = if (((AND) byte_mask (0b0100::word4)) >> 2) = 1 then
              mem_mod asi addr1 byte1 s0 
           else s0;
      s2 = if (((AND) byte_mask (0b0010::word4)) >> 1) = 1 then
              mem_mod asi addr2 byte2 s1 
           else s1;
      s3 = if ((AND) byte_mask (0b0001::word4)) = 1 then
              mem_mod asi addr3 byte3 s2 
           else s2
  in
  s3
"

text ‹The following functions deal with virtual addresses. 
These are based on functions written by David Sanan.›

definition load_word_mem :: "('a) sparc_state  virtua_address  asi_type  
                             machine_word option"
where "load_word_mem state va asi  
let pair = (virt_to_phys va (mmu state) (mem state)) in 
case pair of
  Some pair  ( 
    if mmu_readable (get_acc_flag (snd pair)) asi then 
      (mem_val_w32 asi (fst pair) state)
    else None)
  | None  None"

definition store_word_mem ::"('a) sparc_state  virtua_address  machine_word  
                             word4  asi_type  ('a) sparc_state option"
where "store_word_mem state va wd byte_mask asi  
let pair = (virt_to_phys va (mmu state) (mem state)) in 
case pair of
  Some pair  ( 
    if mmu_writable (get_acc_flag (snd pair)) asi then 
      Some (mem_mod_w32 asi (fst pair) byte_mask wd state)
    else None)
  | None  None"

definition icache_val:: "cache_type  ('a) sparc_state  mem_val_type option"
where "icache_val c state  icache (cache state) c"

definition dcache_val:: "cache_type  ('a) sparc_state  mem_val_type option"
where "dcache_val c state  dcache (cache state) c"

definition icache_mod :: "cache_type  mem_val_type  
                           ('a) sparc_state  ('a) sparc_state"
where "icache_mod c val state  
  statecache := ((cache state)
    icache := (icache (cache state))(c := Some val))
"

definition dcache_mod :: "cache_type  mem_val_type  
                           ('a) sparc_state  ('a) sparc_state"
where "dcache_mod c val state  
  statecache := ((cache state)
    dcache := (dcache (cache state))(c := Some val))
"

text ‹Check if the memory address is in the cache or not.›
definition icache_miss :: "virtua_address  ('a) sparc_state  bool"
where
"icache_miss addr state 
  let line_len = 12;
      tag = (ucast (addr >> line_len))::cache_tag;
      line = (ucast (0b0::word1))::cache_line_size 
  in
  if (icache_val (tag,line) state) = None then True 
  else False    
"

text ‹Check if the memory address is in the cache or not.›
definition dcache_miss :: "virtua_address  ('a) sparc_state  bool"
where
"dcache_miss addr state 
  let line_len = 12;
      tag = (ucast (addr >> line_len))::cache_tag;
      line = (ucast (0b0::word1))::cache_line_size 
  in
  if (dcache_val (tag,line) state) = None then True 
  else False    
"

definition read_data_cache:: "('a) sparc_state  virtua_address  machine_word option"
where "read_data_cache state va 
  let tag = (ucast (va >> 12))::word20;
       offset0 = (AND) ((ucast va)::word12) 0b111111111100;
       offset1 = (OR) offset0 0b000000000001;
       offset2 = (OR) offset0 0b000000000010;
       offset3 = (OR) offset0 0b000000000011;
       r0 = dcache_val (tag,offset0) state;
       r1 = dcache_val (tag,offset1) state;
       r2 = dcache_val (tag,offset2) state;
       r3 = dcache_val (tag,offset3) state
  in
  if r0 = None  r1 = None  r2 = None  r3 = None then
    None
  else
    let byte0 = case r0 of Some v  v;
        byte1 = case r1 of Some v  v;
        byte2 = case r2 of Some v  v;
        byte3 = case r3 of Some v  v 
    in
    Some ((OR) ((OR) ((OR) ((ucast(byte0)) << 24) 
                              ((ucast(byte1)) << 16)) 
                       ((ucast(byte2)) << 8)) 
                (ucast(byte3)))
"

definition read_instr_cache:: "('a) sparc_state  virtua_address  machine_word option"
where "read_instr_cache state va 
  let tag = (ucast (va >> 12))::word20;
       offset0 = (AND) ((ucast va)::word12) 0b111111111100;
       offset1 = (OR) offset0 0b000000000001;
       offset2 = (OR) offset0 0b000000000010;
       offset3 = (OR) offset0 0b000000000011;
       r0 = icache_val (tag,offset0) state;
       r1 = icache_val (tag,offset1) state;
       r2 = icache_val (tag,offset2) state;
       r3 = icache_val (tag,offset3) state
  in
  if r0 = None  r1 = None  r2 = None  r3 = None then
    None
  else
    let byte0 = case r0 of Some v  v;
        byte1 = case r1 of Some v  v;
        byte2 = case r2 of Some v  v;
        byte3 = case r3 of Some v  v 
    in
    Some ((OR) ((OR) ((OR) ((ucast(byte0)) << 24) 
                              ((ucast(byte1)) << 16)) 
                       ((ucast(byte2)) << 8)) 
                (ucast(byte3)))
"

definition add_data_cache :: "('a) sparc_state  virtua_address  machine_word  
  word4  ('a) sparc_state"
where 
 "add_data_cache state va word byte_mask  
   let tag = (ucast (va >> 12))::word20;
       offset0 = (AND) ((ucast va)::word12) 0b111111111100;
       offset1 = (OR) offset0 0b000000000001;
       offset2 = (OR) offset0 0b000000000010;
       offset3 = (OR) offset0 0b000000000011;
       byte0 = (ucast (word >> 24))::mem_val_type;
       byte1 = (ucast (word >> 16))::mem_val_type;
       byte2 = (ucast (word >> 8))::mem_val_type;
       byte3 = (ucast word)::mem_val_type;
       s0 = if (((AND) byte_mask (0b1000::word4)) >> 3) = 1 then
              dcache_mod (tag,offset0) byte0 state
            else state;
       s1 = if (((AND) byte_mask (0b0100::word4)) >> 2) = 1 then
              dcache_mod (tag,offset1) byte1 s0
            else s0;
       s2 = if (((AND) byte_mask (0b0010::word4)) >> 1) = 1 then
              dcache_mod (tag,offset2) byte2 s1
            else s1;
       s3 = if ((AND) byte_mask (0b0001::word4)) = 1 then
              dcache_mod (tag,offset3) byte3 s2
            else s2
   in s3
"

definition add_instr_cache :: "('a) sparc_state  virtua_address  machine_word  
  word4  ('a) sparc_state"
where 
 "add_instr_cache state va word byte_mask  
   let tag = (ucast (va >> 12))::word20;
       offset0 = (AND) ((ucast va)::word12) 0b111111111100;
       offset1 = (OR) offset0 0b000000000001;
       offset2 = (OR) offset0 0b000000000010;
       offset3 = (OR) offset0 0b000000000011;
       byte0 = (ucast (word >> 24))::mem_val_type;
       byte1 = (ucast (word >> 16))::mem_val_type;
       byte2 = (ucast (word >> 8))::mem_val_type;
       byte3 = (ucast word)::mem_val_type;
       s0 = if (((AND) byte_mask (0b1000::word4)) >> 3) = 1 then
              icache_mod (tag,offset0) byte0 state
            else state;
       s1 = if (((AND) byte_mask (0b0100::word4)) >> 2) = 1 then
              icache_mod (tag,offset1) byte1 s0
            else s0;
       s2 = if (((AND) byte_mask (0b0010::word4)) >> 1) = 1 then
              icache_mod (tag,offset2) byte2 s1
            else s1;
       s3 = if ((AND) byte_mask (0b0001::word4)) = 1 then
              icache_mod (tag,offset3) byte3 s2
            else s2
   in s3
"

definition empty_cache ::"cache_context" where "empty_cache c  None"

definition flush_data_cache:: "('a) sparc_state  ('a) sparc_state" where
"flush_data_cache state  statecache := ((cache state)dcache := empty_cache)"

definition flush_instr_cache:: "('a) sparc_state  ('a) sparc_state" where
"flush_instr_cache state  statecache := ((cache state)icache := empty_cache)"

definition flush_cache_all:: "('a) sparc_state  ('a) sparc_state" where
"flush_cache_all state  statecache := ((cache state)
  icache := empty_cache, dcache := empty_cache)"

text ‹Check if the FI or FD bit of CCR is 1. 
If FI is 1 then flush instruction cache. 
If FD is 1 then flush data cache.›
definition ccr_flush :: "('a) sparc_state  ('a) sparc_state"
where
"ccr_flush state 
  let ccr_val = sys_reg_val CCR state;
      ― ‹FI› is bit 21 of CCR›
      fi_val = ((AND) ccr_val (0b00000000001000000000000000000000)) >> 21;
      fd_val = ((AND) ccr_val (0b00000000010000000000000000000000)) >> 22;
      state1 = (if fi_val = 1 then flush_instr_cache state else state)
  in
  if fd_val = 1 then flush_data_cache state1 else state1"

definition get_delayed_pool :: "('a) sparc_state  delayed_write_pool"
where "get_delayed_pool state  dwrite state"

definition exe_pool :: "(int × reg_type × CPU_register)  (int × reg_type × CPU_register)"
where "exe_pool w  case w of (n,v,c)  ((n-1),v,c)"

text ‹Minus 1 to the delayed count for all the members in the set. 
        Assuming all members have delay > 0.›
primrec delayed_pool_minus :: "delayed_write_pool  delayed_write_pool"
where
"delayed_pool_minus [] = []"
|
"delayed_pool_minus (x#xs) = (exe_pool x)#(delayed_pool_minus xs)"

text ‹Add a delayed-write to the pool.›
definition delayed_pool_add :: "(int × reg_type × CPU_register)  
                                ('a) sparc_state  ('a) sparc_state"
where 
"delayed_pool_add dw s 
  let (i,v,cr) = dw in
  if i = 0 then ― ‹Write the value to the register immediately.›
    cpu_reg_mod v cr s
  else ― ‹Add to delayed write pool.›
    let curr_pool = get_delayed_pool s in
    sdwrite := curr_pool@[dw]"

text ‹Remove a delayed-write from the pool. 
        Assume that the delayed-write to be removed has delay 0.
        i.e., it has been executed.›
definition delayed_pool_rm :: "(int × reg_type × CPU_register)  
                               ('a) sparc_state  ('a) sparc_state"
where
"delayed_pool_rm dw s 
  let curr_pool = get_delayed_pool s in
  case dw of (n,v,cr)  
    (if n = 0 then
      sdwrite := List.remove1 dw curr_pool
     else s)
"

text ‹Remove all the entries with delay = 0, i.e., those that are written.›
primrec delayed_pool_rm_written :: "delayed_write_pool  delayed_write_pool"
where
"delayed_pool_rm_written [] = []"
|
"delayed_pool_rm_written (x#xs) = 
  (if fst x = 0 then delayed_pool_rm_written xs else x#(delayed_pool_rm_written xs))    
"

definition annul_val :: "('a) sparc_state  bool"
where "annul_val state  get_annul (state_var state)"

definition annul_mod :: "bool  ('a) sparc_state  ('a) sparc_state"
where "annul_mod b s  sstate_var := write_annul b (state_var s)"

definition reset_trap_val :: "('a) sparc_state  bool"
where "reset_trap_val state  get_reset_trap (state_var state)"

definition reset_trap_mod :: "bool  ('a) sparc_state  ('a) sparc_state"
where "reset_trap_mod b s  sstate_var := write_reset_trap b (state_var s)"

definition exe_mode_val :: "('a) sparc_state  bool"
where "exe_mode_val state  get_exe_mode (state_var state)"

definition exe_mode_mod :: "bool  ('a) sparc_state  ('a) sparc_state"
where "exe_mode_mod b s  sstate_var := write_exe_mode b (state_var s)"

definition reset_mode_val :: "('a) sparc_state  bool"
where "reset_mode_val state  get_reset_mode (state_var state)"

definition reset_mode_mod :: "bool  ('a) sparc_state  ('a) sparc_state"
where "reset_mode_mod b s  sstate_var := write_reset_mode b (state_var s)"

definition err_mode_val :: "('a) sparc_state  bool"
where "err_mode_val state  get_err_mode (state_var state)"

definition err_mode_mod :: "bool  ('a) sparc_state  ('a) sparc_state"
where "err_mode_mod b s  sstate_var := write_err_mode b (state_var s)"

definition ticc_trap_type_val :: "('a) sparc_state  word7"
where "ticc_trap_type_val state  get_ticc_trap_type (state_var state)"

definition ticc_trap_type_mod :: "word7  ('a) sparc_state  ('a) sparc_state"
where "ticc_trap_type_mod w s  sstate_var := write_ticc_trap_type w (state_var s)"

definition interrupt_level_val :: "('a) sparc_state  word3"
where "interrupt_level_val state  get_interrupt_level (state_var state)"

definition interrupt_level_mod :: "word3  ('a) sparc_state  ('a) sparc_state"
where "interrupt_level_mod w s  sstate_var := write_interrupt_level w (state_var s)"

definition store_barrier_pending_val :: "('a) sparc_state  bool"
where "store_barrier_pending_val state  
  get_store_barrier_pending (state_var state)"

definition store_barrier_pending_mod :: "bool  
  ('a) sparc_state  ('a) sparc_state"
where "store_barrier_pending_mod w s 
  sstate_var := write_store_barrier_pending w (state_var s)"

definition pb_block_ldst_byte_val :: "virtua_address  ('a) sparc_state
   bool"
where "pb_block_ldst_byte_val add state 
  (atm_ldst_byte (state_var state)) add"

definition pb_block_ldst_byte_mod :: "virtua_address  bool  
  ('a) sparc_state  ('a) sparc_state"
where "pb_block_ldst_byte_mod add b s 
  sstate_var := ((state_var s)
    atm_ldst_byte := (atm_ldst_byte (state_var s))(add := b))"

text ‹We only read the address such that add mod 4 = 0. 
  add mod 4 represents the current word.›
definition pb_block_ldst_word_val :: "virtua_address  ('a) sparc_state
   bool"
where "pb_block_ldst_word_val add state 
  let add0 = ((AND) add (0b11111111111111111111111111111100::word32)) in
  (atm_ldst_word (state_var state)) add0"

text ‹We only write the address such that add mod 4 = 0.
  add mod 4 represents the current word.›
definition pb_block_ldst_word_mod :: "virtua_address  bool  
  ('a) sparc_state  ('a) sparc_state"
where "pb_block_ldst_word_mod add b s 
  let add0 = ((AND) add (0b11111111111111111111111111111100::word32)) in
  sstate_var := ((state_var s)
    atm_ldst_word := (atm_ldst_word (state_var s))(add0 := b))"

definition get_trap_set :: "('a) sparc_state  Trap set"
where "get_trap_set state  (traps state)"

definition add_trap_set :: "Trap  ('a) sparc_state  ('a) sparc_state"
where "add_trap_set t s  straps := (traps s)  {t}"

definition emp_trap_set :: "('a) sparc_state  ('a) sparc_state"
where "emp_trap_set s  straps := {}"

definition state_undef:: "('a) sparc_state  bool"
where "state_undef state  (undef state)"

text ‹The memory_read› interface that conforms with the SPARCv8 manual.›
definition memory_read :: "asi_type  virtua_address  
                           ('a) sparc_state  
                           ((word32 option) × ('a) sparc_state)"
where "memory_read asi addr state 
  let asi_int = uint asi in ― ‹See Page 25 and 35 for ASI usage in LEON 3FT.›
  if asi_int = 1 then ― ‹Forced cache miss.›
    ― ‹Directly read from memory.›
    let r1 = load_word_mem state addr (word_of_int 8) in
    if r1 = None then
      let r2 = load_word_mem state addr (word_of_int 10) in
      if r2 = None then
        (None,state)
      else (r2,state)
    else (r1,state)
  else if asi_int = 2 then ― ‹System registers.›
    ― ‹See Table 19, Page 34 for System Register address map in LEON 3FT.›
    if uint addr = 0 then ― ‹Cache control register.›
      ((Some (sys_reg_val CCR state)), state)
    else if uint addr = 8 then ― ‹Instruction cache configuration register.›
      ((Some (sys_reg_val ICCR state)), state)
    else if uint addr = 12 then ― ‹Data cache configuration register.›
      ((Some (sys_reg_val DCCR state)), state)
    else ― ‹Invalid address.›
      (None, state)
  else if asi_int  {8,9} then ― ‹Access instruction memory.›
    let ccr_val = (sys_reg state) CCR in
    if ccr_val AND 1  0 then ― ‹Cache is enabled. Update cache.›
    ― ‹We don't go through the tradition, i.e., read from cache first,›
    ― ‹if the address is not cached, then read from memory,›
    ― ‹because performance is not an issue here.›
    ― ‹Thus we directly read from memory and update the cache.›
      let data = load_word_mem state addr asi in
      case data of
      Some w  (Some w,(add_instr_cache state addr w (0b1111::word4)))
      |None  (None, state)
    else ― ‹Cache is disabled. Just read from memory.›
      ((load_word_mem state addr asi),state)
  else if asi_int  {10,11} then ― ‹Access data memory.›
    let ccr_val = (sys_reg state) CCR in
    if ccr_val AND 1  0 then ― ‹Cache is enabled. Update cache.›
    ― ‹We don't go through the tradition, i.e., read from cache first,›
    ― ‹if the address is not cached, then read from memory,›
    ― ‹because performance is not an issue here.›
    ― ‹Thus we directly read from memory and update the cache.›
      let data = load_word_mem state addr asi in
      case data of
      Some w  (Some w,(add_data_cache state addr w (0b1111::word4)))
      |None  (None, state)
    else ― ‹Cache is disabled. Just read from memory.›
      ((load_word_mem state addr asi),state)
  ― ‹We don't access instruction cache tag. i.e., asi = 12›.›
  else if asi_int = 13 then ― ‹Read instruction cache data.›
    let cache_result = read_instr_cache state addr in
    case cache_result of
    Some w  (Some w, state)
    |None  (None, state)
  ― ‹We don't access data cache tag. i.e., asi = 14›.›
  else if asi_int = 15 then ― ‹Read data cache data.›
    let cache_result = read_data_cache state addr in
    case cache_result of
    Some w  (Some w, state)
    |None  (None, state)
  else if asi_int  {16,17} then ― ‹Flush entire instruction/data cache.›
    (None, state) ― ‹Has no effect for memory read.›
  else if asi_int  {20,21} then ― ‹MMU diagnostic cache access.›
    (None, state) ― ‹Not considered in this model.›
  else if asi_int = 24 then ― ‹Flush cache and TLB in LEON3.›
    ― ‹But is not used for memory read.›
    (None, state)
  else if asi_int = 25 then ― ‹MMU registers.›
    ― ‹Treat MMU registers as memory addresses that are not in the main memory.›
    ((mmu_reg_val (mmu state) addr), state) 
  else if asi_int = 28 then ― ‹MMU bypass.›
    ― ‹Directly use addr as a physical address.›
    ― ‹Append 0000 in the front of addr.›
    ― ‹In this case, (ucast addr) suffices.›
    ((mem_val_w32 asi (ucast addr) state), state)
  else if asi_int = 29 then ― ‹MMU diagnostic access.›
    (None, state) ― ‹Not considered in this model.›
  else ― ‹Not considered in this model.›
    (None, state)
"

text ‹Get the value of a memory address and an ASI.›
definition mem_val_asi:: "asi_type  phys_address  
                      ('a) sparc_state  mem_val_type option"
where "mem_val_asi asi add state  (mem state) asi add"

text ‹Check if an address is used in ASI 9 or 11.›
definition sup_addr :: "phys_address  ('a) sparc_state  bool"
where
"sup_addr addr state 
  let addr' = (AND) addr 0b111111111111111111111111111111111100;
      addr0 = (OR) addr' 0b000000000000000000000000000000000000;
      addr1 = (OR) addr' 0b000000000000000000000000000000000001;
      addr2 = (OR) addr' 0b000000000000000000000000000000000010;
      addr3 = (OR) addr' 0b000000000000000000000000000000000011;
      r0 = mem_val_asi 9 addr0 state;
      r1 = mem_val_asi 9 addr1 state;
      r2 = mem_val_asi 9 addr2 state;
      r3 = mem_val_asi 9 addr3 state;
      r4 = mem_val_asi 11 addr0 state;
      r5 = mem_val_asi 11 addr1 state;
      r6 = mem_val_asi 11 addr2 state;
      r7 = mem_val_asi 11 addr3 state
  in
  if r0 = None  r1 = None  r2 = None  r3 = None 
     r4 = None  r5 = None  r6 = None  r7 = None
  then False
  else True
"

text ‹The memory_write› interface that conforms with SPARCv8 manual.›
text ‹LEON3 forbids user to write an address in ASI 9 and 11.›
definition memory_write_asi :: "asi_type  virtua_address  word4  word32  
                            ('a) sparc_state  
                            ('a) sparc_state option"
where
"memory_write_asi asi addr byte_mask data_w32 state  
  let asi_int = uint asi; ― ‹See Page 25 and 35 for ASI usage in LEON 3FT.›
      psr_val = cpu_reg_val PSR state;
      s_val = get_S psr_val
  in 
  if asi_int = 1 then ― ‹Forced cache miss.›
    ― ‹Directly write to memory.›
    ― ‹Assuming writing into asi = 10›.›
    store_word_mem state addr data_w32 byte_mask (word_of_int 10) 
  else if asi_int = 2 then ― ‹System registers.›
    ― ‹See Table 19, Page 34 for System Register address map in LEON 3FT.›
    if uint addr = 0 then ― ‹Cache control register.›
      let s1 = (sys_reg_mod data_w32 CCR state) in
      ― ‹Flush the instruction cache if FI of CCR is 1;›
      ― ‹flush the data cache if FD of CCR is 1.›
      Some (ccr_flush s1)
    else if uint addr = 8 then ― ‹Instruction cache configuration register.›
      Some (sys_reg_mod data_w32 ICCR state)
    else if uint addr = 12 then ― ‹Data cache configuration register.›
      Some (sys_reg_mod data_w32 DCCR state)
    else ― ‹Invalid address.›
      None
  else if asi_int  {8,9} then ― ‹Access instruction memory.›
    ― ‹Write to memory. LEON3 does write-through. Both cache and the memory are updated.›
    let ns = add_instr_cache state addr data_w32 byte_mask in
    store_word_mem ns addr data_w32 byte_mask asi
  else if asi_int  {10,11} then ― ‹Access data memory.›
    ― ‹Write to memory. LEON3 does write-through. Both cache and the memory are updated.›
    let ns = add_data_cache state addr data_w32 byte_mask in
    store_word_mem ns addr data_w32 byte_mask asi
  ― ‹We don't access instruction cache tag. i.e., asi = 12›.›
  else if asi_int = 13 then ― ‹Write instruction cache data.›
    Some (add_instr_cache state addr data_w32 (0b1111::word4))
  ― ‹We don't access data cache tag. i.e., asi = 14.›
  else if asi_int = 15 then ― ‹Write data cache data.›
    Some (add_data_cache state addr data_w32 (0b1111::word4))
  else if asi_int = 16 then ― ‹Flush instruction cache.›
    Some (flush_instr_cache state)
  else if asi_int = 17 then ― ‹Flush data cache.›
    Some (flush_data_cache state)
  else if asi_int  {20,21} then ― ‹MMU diagnostic cache access.›
    None ― ‹Not considered in this model.›
  else if asi_int = 24 then ― ‹Flush TLB and cache in LEON3.›
    ― ‹We don't consider TLB here.›
    Some (flush_cache_all state)
  else if asi_int = 25 then ― ‹MMU registers.›
    ― ‹Treat MMU registers as memory addresses that are not in the main memory.›
    let mmu_state' = mmu_reg_mod (mmu state) addr data_w32 in
    case mmu_state' of
    Some mmus  Some (statemmu := mmus)
    |None  None 
  else if asi_int = 28 then ― ‹MMU bypass.›
    ― ‹Write to virtual address as physical address.›
    ― ‹Append 0000 in front of addr.›
    Some (mem_mod_w32 asi (ucast addr) byte_mask data_w32 state)
  else if asi_int = 29 then ― ‹MMU diagnostic access.›
    None ― ‹Not considered in this model.›
  else ― ‹Not considered in this model.›
    None
"

definition memory_write :: "asi_type  virtua_address  word4  word32  
                            ('a) sparc_state  
                            ('a) sparc_state option"
where
"memory_write asi addr byte_mask data_w32 state  
  let result = memory_write_asi asi addr byte_mask data_w32 state in
  case result of 
  None  None
  | Some s1  Some (store_barrier_pending_mod False s1)"

text ‹monad for sequential operations over the register representation›
type_synonym ('a,'e) sparc_state_monad = "(('a) sparc_state,'e) det_monad" 

text ‹Given a word32 value, a cpu register, 
        write the value in the cpu register.›
definition write_cpu :: "word32  CPU_register  ('a,unit) sparc_state_monad"
where "write_cpu w cr 
  do
    modify (λs. (cpu_reg_mod w cr s));
    return ()
  od"

definition write_cpu_tt :: "word8  ('a,unit) sparc_state_monad"
where "write_cpu_tt w 
  do
    tbr_val  gets (λs. (cpu_reg_val TBR s));
    new_tbr_val  gets (λs. (write_tt w tbr_val));
    write_cpu new_tbr_val TBR;
    return ()
  od"

text ‹Given a word32 value, a word4 window, a user register, 
        write the value in the user register. 
        N.B. CWP is a 5 bit value, but we only use the last 4 bits,
        since there are only 16 windows.›
definition write_reg :: "word32  ('a::len) word  user_reg_type  
  ('a,unit) sparc_state_monad"
where "write_reg w win ur 
  do
    modify (λs.(user_reg_mod w win ur s));
    return ()
  od"

definition set_annul :: "bool  ('a,unit) sparc_state_monad"
where "set_annul b 
  do
    modify (λs. (annul_mod b s));
    return ()
  od"

definition set_reset_trap :: "bool  ('a,unit) sparc_state_monad"
where "set_reset_trap b 
  do
    modify (λs. (reset_trap_mod b s));
    return ()
  od"

definition set_exe_mode :: "bool  ('a,unit) sparc_state_monad"
where "set_exe_mode b 
  do
    modify (λs. (exe_mode_mod b s));
    return ()
  od"

definition set_reset_mode :: "bool  ('a,unit) sparc_state_monad"
where "set_reset_mode b 
  do
    modify (λs. (reset_mode_mod b s));
    return ()
  od" 

definition set_err_mode :: "bool  ('a,unit) sparc_state_monad"
where "set_err_mode b 
  do
    modify (λs. (err_mode_mod b s));
    return ()
  od"

fun get_delayed_0 :: "(int × reg_type × CPU_register) list  
  (int × reg_type × CPU_register) list"
where
"get_delayed_0 [] = []"
|
"get_delayed_0 (x # xs) = 
  (if fst x = 0 then x # (get_delayed_0 xs)
  else get_delayed_0 xs)"

text ‹Get a list of delayed-writes with delay 0.›
definition get_delayed_write :: "delayed_write_pool  (int × reg_type × CPU_register) list"
where
"get_delayed_write dwp  get_delayed_0 dwp"

definition delayed_write :: "(int × reg_type × CPU_register)  ('a) sparc_state 
  ('a) sparc_state"
where "delayed_write dw s 
  let (n,v,r) = dw in
  if n = 0 then
    cpu_reg_mod v r s
  else s"

primrec delayed_write_all :: "(int × reg_type × CPU_register) list 
  ('a) sparc_state  ('a) sparc_state"
where "delayed_write_all [] s = s"
|"delayed_write_all (x # xs) s =
  delayed_write_all xs (delayed_write x s)"

primrec delayed_pool_rm_list :: "(int × reg_type × CPU_register) list 
  ('a) sparc_state  ('a) sparc_state"
where "delayed_pool_rm_list [] s = s"
|"delayed_pool_rm_list (x # xs) s =
  delayed_pool_rm_list xs (delayed_pool_rm x s)"

definition delayed_pool_write :: "('a) sparc_state  ('a) sparc_state"
where "delayed_pool_write s 
  let dwp0 = get_delayed_pool s;
      dwp1 = delayed_pool_minus dwp0;
      wl = get_delayed_write dwp1;
      s1 = delayed_write_all wl s;
      s2 = delayed_pool_rm_list wl s1 
  in s2"

definition raise_trap :: "Trap  ('a,unit) sparc_state_monad"
where "raise_trap t 
  do
    modify (λs. (add_trap_set t s));
    return ()
  od"

end

Theory Sparc_Instruction

(*
 * Copyright 2016, NTU
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * Author: Zhe Hou, David Sanan.
 *)

section ‹SPARC instruction model›
theory Sparc_Instruction
imports Main Sparc_Types Sparc_State "HOL-Eisbach.Eisbach_Tools"
begin
text‹
This theory provides a formal model for assembly instruction to be executed in the model.

An instruction is defined as a tuple composed of a @{term sparc_operation} element,
defining the operation the instruction carries out, and a list of operands 
@{term inst_operand}. @{term inst_operand} can be a user register @{term user_reg} 
or a memory address @{term mem_add_type}.
›
datatype inst_operand = 
W5 word5
|W30 word30
|W22 word22
|Cond  word4
|Flag word1
|Asi asi_type
|Simm13 word13 
|Opf word9
|Imm7 word7

primrec get_operand_w5::"inst_operand  word5"
where "get_operand_w5 (W5 r) = r"

primrec get_operand_w30::"inst_operand  word30"
where "get_operand_w30 (W30 r) = r"

primrec get_operand_w22::"inst_operand  word22"
where "get_operand_w22 (W22 r) = r"

primrec get_operand_cond::"inst_operand  word4"
where "get_operand_cond (Cond r) = r"

primrec get_operand_flag::"inst_operand  word1"
where "get_operand_flag (Flag r) = r"

primrec get_operand_asi::"inst_operand  asi_type"
where "get_operand_asi (Asi r) = r"

primrec get_operand_simm13::"inst_operand  word13"
where "get_operand_simm13 (Simm13 r) = r"

primrec get_operand_opf::"inst_operand  word9"
where "get_operand_opf (Opf r) = r"

primrec get_operand_imm7:: "inst_operand  word7"
where "get_operand_imm7 (Imm7 r) = r"

type_synonym instruction = "(sparc_operation × inst_operand list)"

definition get_op::"word32  int"
where "get_op w  uint (w >> 30)"

definition get_op2::"word32  int"
where "get_op2 w  
  let mask_op2 = 0b00000001110000000000000000000000 in
  uint (((AND) mask_op2 w) >> 22)"

definition get_op3::"word32  int"
where "get_op3 w  
  let mask_op3 = 0b00000001111110000000000000000000 in 
  uint (((AND) mask_op3 w) >> 19)"

definition get_disp30::"word32  int"
where "get_disp30 w  
  let mask_disp30 = 0b00111111111111111111111111111111 in
  uint ((AND) mask_disp30 w)"

definition get_a::"word32  int"
where "get_a w 
  let mask_a = 0b00100000000000000000000000000000 in
  uint (((AND) mask_a w) >> 29)"

definition get_cond::"word32  int"
where "get_cond w 
  let mask_cond = 0b00011110000000000000000000000000 in
  uint (((AND) mask_cond w) >> 25)"

definition get_disp_imm22::"word32  int"
where "get_disp_imm22 w 
  let mask_disp_imm22 = 0b00000000001111111111111111111111 in
  uint ((AND) mask_disp_imm22 w)"

definition get_rd::"word32  int"
where "get_rd w 
  let mask_rd = 0b00111110000000000000000000000000 in
  uint (((AND) mask_rd w) >> 25)"

definition get_rs1::"word32  int"
where "get_rs1 w 
  let mask_rs1 = 0b00000000000001111100000000000000 in
  uint (((AND) mask_rs1 w) >> 14)"

definition get_i::"word32  int"
where "get_i w 
  let mask_i = 0b00000000000000000010000000000000 in
  uint (((AND) mask_i w) >> 13)"

definition get_opf::"word32  int"
where "get_opf w  
  let mask_opf = 0b00000000000000000011111111100000 in
  uint (((AND) mask_opf w) >> 5)"

definition get_rs2::"word32  int"
where "get_rs2 w 
  let mask_rs2 = 0b00000000000000000000000000011111 in
  uint ((AND) mask_rs2 w)"

definition get_simm13::"word32  int"
where "get_simm13 w 
  let mask_simm13 = 0b00000000000000000001111111111111 in
  uint ((AND) mask_simm13 w)"

definition get_asi::"word32  int"
where "get_asi w 
  let mask_asi = 0b00000000000000000001111111100000 in
  uint (((AND) mask_asi w) >> 5)"

definition get_trap_cond:: "word32  int"
where "get_trap_cond w 
  let mask_cond = 0b00011110000000000000000000000000 in
  uint (((AND) mask_cond w) >> 25)"

definition get_trap_imm7:: "word32  int"
where "get_trap_imm7 w 
  let mask_imm7 = 0b00000000000000000000000001111111 in
  uint ((AND) mask_imm7 w)"

definition parse_instr_f1::"word32  
  (Exception list + instruction)"
where ― ‹CALL›, with a single operand disp30+"00"›
"parse_instr_f1 w                                                      
  Inr (call_type CALL,[W30 (word_of_int (get_disp30 w))])"

definition parse_instr_f2::"word32  
  (Exception list + instruction)"
where "parse_instr_f2 w 
  let op2 = get_op2 w in
  if op2 = uint(0b100::word3) then ― ‹SETHI› or NOP›
    let rd = get_rd w in
    let imm22 = get_disp_imm22 w in
    if rd = 0  imm22 = 0 then ― ‹NOP›
      Inr (nop_type NOP,[])
    else ― ‹SETHI›, with operands [imm22,rd]›
      Inr (sethi_type SETHI,[(W22 (word_of_int imm22)),
                   (W5 (word_of_int rd))])
  else if op2 = uint(0b010::word3) then ― ‹Bicc›, with operands [a,disp22]›
    let cond = get_cond w in
    let flaga = Flag (word_of_int (get_a w)) in
    let disp22 = W22 (word_of_int (get_disp_imm22 w)) in
    if cond = uint(0b0001::word4) then ― ‹BE›
      Inr (bicc_type BE,[flaga,disp22])
    else if cond = uint(0b1001::word4) then ― ‹BNE›
      Inr (bicc_type BNE,[flaga,disp22])
    else if cond = uint(0b1100::word4) then ― ‹BGU›
      Inr (bicc_type BGU,[flaga,disp22])
    else if cond = uint(0b0010::word4) then ― ‹BLE›
      Inr (bicc_type BLE,[flaga,disp22])
    else if cond = uint(0b0011::word4) then ― ‹BL›
      Inr (bicc_type BL,[flaga,disp22])
    else if cond = uint(0b1011::word4) then ― ‹BGE›
      Inr (bicc_type BGE,[flaga,disp22])
    else if cond = uint(0b0110::word4) then ― ‹BNEG›
      Inr (bicc_type BNEG,[flaga,disp22])
    else if cond = uint(0b1010::word4) then ― ‹BG›
      Inr (bicc_type BG,[flaga,disp22])
    else if cond = uint(0b0101::word4) then ― ‹BCS›
      Inr (bicc_type BCS,[flaga,disp22])
    else if cond = uint(0b0100::word4) then ― ‹BLEU›
      Inr (bicc_type BLEU,[flaga,disp22])
    else if cond = uint(0b1101::word4) then ― ‹BCC›
      Inr (bicc_type BCC,[flaga,disp22])
    else if cond = uint(0b1000::word4) then ― ‹BA›
      Inr (bicc_type BA,[flaga,disp22])
    else if cond = uint(0b0000::word4) then ― ‹BN›
      Inr (bicc_type BN,[flaga,disp22])
    else if cond = uint(0b1110::word4) then ― ‹BPOS›
      Inr (bicc_type BPOS,[flaga,disp22])
    else if cond = uint(0b1111::word4) then ― ‹BVC›
      Inr (bicc_type BVC,[flaga,disp22])
    else if cond = uint(0b0111::word4) then ― ‹BVS›
      Inr (bicc_type BVS,[flaga,disp22])
    else Inl [invalid_cond_f2]
  else Inl [invalid_op2_f2]
"

text ‹We don't consider floating-point operations, 
        so we don't consider the third type of format 3.›
definition parse_instr_f3::"word32  (Exception list + instruction)"
where "parse_instr_f3 w 
  let this_op = get_op w in
  let rd = get_rd w in
  let op3 = get_op3 w in
  let rs1 = get_rs1 w in
  let flagi = get_i w in
  let asi = get_asi w in
  let rs2 = get_rs2 w in
  let simm13 = get_simm13 w in
  if this_op = uint(0b11::word2) then ― ‹Load and Store›
  ― ‹If an instruction accesses alternative space but flagi = 1›,›
  ― ‹may need to throw a trap.›
    if op3 = uint(0b001001::word6) then ― ‹LDSB›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type LDSB,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type LDSB,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011001::word6) then ― ‹LDSBA›
       Inr (load_store_type LDSBA,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (Asi (word_of_int asi)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b001010::word6) then ― ‹LDSH›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type LDSH,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type LDSH,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011010::word6) then ― ‹LDSHA›
       Inr (load_store_type LDSHA,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (Asi (word_of_int asi)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b000001::word6) then ― ‹LDUB›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type LDUB,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type LDUB,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b010001::word6) then ― ‹LDUBA›
       Inr (load_store_type LDUBA,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (Asi (word_of_int asi)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b000010::word6) then ― ‹LDUH›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type LDUH,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type LDUH,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b010010::word6) then ― ‹LDUHA›
       Inr (load_store_type LDUHA,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (Asi (word_of_int asi)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b000000::word6) then ― ‹LD›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type LD,[(Flag (word_of_int flagi)),
                      (W5 (word_of_int rs1)),
                      (Simm13 (word_of_int simm13)),
                      (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type LD,[(Flag (word_of_int flagi)),
                      (W5 (word_of_int rs1)),
                      (W5 (word_of_int rs2)),
                      (W5 (word_of_int rd))])
    else if op3 = uint(0b010000::word6) then ― ‹LDA›
       Inr (load_store_type LDA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (Asi (word_of_int asi)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000011::word6) then ― ‹LDD›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type LDD,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type LDD,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010011::word6) then ― ‹LDDA›
       Inr (load_store_type LDDA,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (Asi (word_of_int asi)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b001101::word6) then ― ‹LDSTUB›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type LDSTUB,[(Flag (word_of_int flagi)),
                      (W5 (word_of_int rs1)),
                      (Simm13 (word_of_int simm13)),
                      (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type LDSTUB,[(Flag (word_of_int flagi)),
                      (W5 (word_of_int rs1)),
                      (W5 (word_of_int rs2)),
                      (W5 (word_of_int rd))])
    else if op3 = uint(0b011101::word6) then ― ‹LDSTUBA›
       Inr (load_store_type LDSTUBA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (Asi (word_of_int asi)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000101::word6) then ― ‹STB›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type STB,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type STB,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010101::word6) then ― ‹STBA›
       Inr (load_store_type STBA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (Asi (word_of_int asi)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000110::word6) then ― ‹STH›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type STH,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type STH,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010110::word6) then ― ‹STHA›
       Inr (load_store_type STHA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (Asi (word_of_int asi)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000100::word6) then ― ‹ST›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type ST,[(Flag (word_of_int flagi)),
                      (W5 (word_of_int rs1)),
                      (Simm13 (word_of_int simm13)),
                      (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type ST,[(Flag (word_of_int flagi)),
                      (W5 (word_of_int rs1)),
                      (W5 (word_of_int rs2)),
                      (W5 (word_of_int rd))])
    else if op3 = uint(0b010100::word6) then ― ‹STA›
       Inr (load_store_type STA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (Asi (word_of_int asi)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000111::word6) then ― ‹STD›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type STD,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type STD,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010111::word6) then ― ‹STDA›
       Inr (load_store_type STDA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (Asi (word_of_int asi)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b001111::word6) then ― ‹SWAP›
      if flagi = 1 then ― ‹Operant list is [i,rs1,simm13,rd]›
         Inr (load_store_type SWAP,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
      else ― ‹Operant list is [i,rs1,rs2,rd]›
         Inr (load_store_type SWAP,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b011111::word6) then ― ‹SWAPA›
       Inr (load_store_type SWAPA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (Asi (word_of_int asi)),
                       (W5 (word_of_int rd))])
    else Inl [invalid_op3_f3_op11]
  else if this_op = uint(0b10::word2) then ― ‹Others›
    if op3 = uint(0b111000::word6) then ― ‹JMPL›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (ctrl_type JMPL,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (ctrl_type JMPL,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b111001::word6) then ― ‹RETT›
      if flagi = 0 then ― ‹return [i,rs1,rs2]›
         Inr (ctrl_type RETT,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2))])
      else ― ‹return [i,rs1,simm13]›
         Inr (ctrl_type RETT,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13))])
    ― ‹The following are Read and Write instructions,›
    ― ‹only return [rs1,rd]› as operand.›
    else if op3 = uint(0b101000::word6)  rs1  0 then ― ‹RDASR›
      if rs1 = uint(0b01111::word6)  rd = 0 then ― ‹STBAR› is a special case of RDASR›
        Inr (load_store_type STBAR,[])
      else Inr (sreg_type RDASR,[(W5 (word_of_int rs1)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b101000::word6)  rs1 = 0 then ― ‹RDY›
       Inr (sreg_type RDY,[(W5 (word_of_int rs1)),
                     (W5 (word_of_int rd))])
    else if op3 = uint(0b101001::word6) then ― ‹RDPSR›
       Inr (sreg_type RDPSR,[(W5 (word_of_int rs1)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b101010::word6) then ― ‹RDWIM›
       Inr (sreg_type RDWIM,[(W5 (word_of_int rs1)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b101011::word6) then ― ‹RDTBR›
       Inr (sreg_type RDTBR,[(W5 (word_of_int rs1)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b110000::word6)  rd  0 then ― ‹WRASR›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (sreg_type WRASR,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (sreg_type WRASR,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b110000::word6)  rd = 0 then ― ‹WRY›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (sreg_type WRY,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (sreg_type WRY,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b110001::word6) then ― ‹WRPSR›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (sreg_type WRPSR,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (sreg_type WRPSR,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b110010::word6) then ― ‹WRWIM›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (sreg_type WRWIM,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (sreg_type WRWIM,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b110011::word6) then ― ‹WRTBR›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (sreg_type WRTBR,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (sreg_type WRTBR,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13)),
                         (W5 (word_of_int rd))])
    ― ‹FLUSH› instruction›
    else if op3 = uint(0b111011::word6) then ― ‹FLUSH›
      if flagi = 0 then ― ‹return [1,rs1,rs2]›
         Inr (load_store_type FLUSH,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2))])
      else ― ‹return [i,rs1,simm13]›
         Inr (load_store_type FLUSH,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13))])
    ― ‹The following are arithmetic instructions.›
    else if op3 = uint(0b000001::word6) then ― ‹AND›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ANDs,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ANDs,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b010001::word6) then ― ‹ANDcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ANDcc,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ANDcc,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b000101::word6) then ― ‹ANDN›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ANDN,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ANDN,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b010101::word6) then ― ‹ANDNcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ANDNcc,[(Flag (word_of_int flagi)),
                          (W5 (word_of_int rs1)),
                          (W5 (word_of_int rs2)),
                          (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ANDNcc,[(Flag (word_of_int flagi)),
                          (W5 (word_of_int rs1)),
                          (Simm13 (word_of_int simm13)),
                          (W5 (word_of_int rd))])
    else if op3 = uint(0b000010::word6) then ― ‹OR›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ORs,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ORs,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010010::word6) then ― ‹ORcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ORcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ORcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b000110::word6) then ― ‹ORN›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ORN,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ORN,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010110::word6) then ― ‹ORNcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type ORNcc,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type ORNcc,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000011::word6) then ― ‹XORs›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type XORs,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type XORs,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b010011::word6) then ― ‹XORcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type XORcc,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type XORcc,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000111::word6) then ― ‹XNOR›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type XNOR,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type XNOR,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b010111::word6) then ― ‹XNORcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (logic_type XNORcc,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (logic_type XNORcc,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b100101::word6) then ― ‹SLL›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (shift_type SLL,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,shcnt,rd]›
        let shcnt = rs2 in
         Inr (shift_type SLL,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int shcnt)),
                       (W5 (word_of_int rd))])
    else if op3 = uint (0b100110::word6) then ― ‹SRL›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (shift_type SRL,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,shcnt,rd]›
        let shcnt = rs2 in
         Inr (shift_type SRL,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int shcnt)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b100111::word6) then ― ‹SRA›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (shift_type SRA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,shcnt,rd]›
        let shcnt = rs2 in
         Inr (shift_type SRA,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int shcnt)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b000000::word6) then ― ‹ADD›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type ADD,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type ADD,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010000::word6) then ― ‹ADDcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type ADDcc,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type ADDcc,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b001000::word6) then ― ‹ADDX›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type ADDX,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type ADDX,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011000::word6) then ― ‹ADDXcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type ADDXcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type ADDXcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b100000::word6) then ― ‹TADDcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type TADDcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type TADDcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b100010::word6) then ― ‹TADDccTV›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type TADDccTV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type TADDccTV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b000100::word6) then ― ‹SUB›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SUB,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (W5 (word_of_int rs2)),
                       (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SUB,[(Flag (word_of_int flagi)),
                       (W5 (word_of_int rs1)),
                       (Simm13 (word_of_int simm13)),
                       (W5 (word_of_int rd))])
    else if op3 = uint(0b010100::word6) then ― ‹SUBcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SUBcc,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (W5 (word_of_int rs2)),
                         (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SUBcc,[(Flag (word_of_int flagi)),
                         (W5 (word_of_int rs1)),
                         (Simm13 (word_of_int simm13)),
                         (W5 (word_of_int rd))])
    else if op3 = uint(0b001100::word6) then ― ‹SUBX›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SUBX,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SUBX,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011100::word6) then ― ‹SUBXcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SUBXcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SUBXcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b100001::word6) then ― ‹TSUBcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type TSUBcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type TSUBcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b100011::word6) then ― ‹TSUBccTV›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type TSUBccTV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type TSUBccTV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b100100::word6) then ― ‹MULScc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type MULScc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type MULScc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b001010::word6) then ― ‹UMUL›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type UMUL,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type UMUL,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011010::word6) then ― ‹UMULcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type UMULcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type UMULcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b001011::word6) then ― ‹SMUL›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SMUL,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SMUL,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011011::word6) then ― ‹SMULcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SMULcc,[(Flag (word_of_int flagi)),
                          (W5 (word_of_int rs1)),
                          (W5 (word_of_int rs2)),
                          (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SMULcc,[(Flag (word_of_int flagi)),
                          (W5 (word_of_int rs1)),
                          (Simm13 (word_of_int simm13)),
                          (W5 (word_of_int rd))])
    else if op3 = uint(0b001110::word6) then ― ‹UDIV›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type UDIV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type UDIV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011110::word6) then ― ‹UDIVcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type UDIVcc,[(Flag (word_of_int flagi)),
                          (W5 (word_of_int rs1)),
                          (W5 (word_of_int rs2)),
                          (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type UDIVcc,[(Flag (word_of_int flagi)),
                          (W5 (word_of_int rs1)),
                          (Simm13 (word_of_int simm13)),
                          (W5 (word_of_int rd))])
    else if op3 = uint(0b001111::word6) then ― ‹SDIV›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SDIV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SDIV,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b011111::word6) then ― ‹SDIVcc›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (arith_type SDIVcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (arith_type SDIVcc,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b111100::word6) then ― ‹SAVE›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (ctrl_type SAVE,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (W5 (word_of_int rs2)),
                        (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (ctrl_type SAVE,[(Flag (word_of_int flagi)),
                        (W5 (word_of_int rs1)),
                        (Simm13 (word_of_int simm13)),
                        (W5 (word_of_int rd))])
    else if op3 = uint(0b111101::word6) then ― ‹RESTORE›
      if flagi = 0 then ― ‹return [i,rs1,rs2,rd]›
         Inr (ctrl_type RESTORE,[(Flag (word_of_int flagi)),
                           (W5 (word_of_int rs1)),
                           (W5 (word_of_int rs2)),
                           (W5 (word_of_int rd))])
      else ― ‹return [i,rs1,simm13,rd]›
         Inr (ctrl_type RESTORE,[(Flag (word_of_int flagi)),
                           (W5 (word_of_int rs1)),
                           (Simm13 (word_of_int simm13)),
                           (W5 (word_of_int rd))])
    else if op3 = uint(0b111010::word6) then ― ‹Ticc›
      let trap_cond = get_trap_cond w in
      let trap_imm7 = get_trap_imm7 w in
      if trap_cond = uint(0b1000::word4) then ― ‹TA›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TA,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TA,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0000::word4) then ― ‹TN›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TN,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TN,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b1001::word4) then ― ‹TNE›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TNE,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TNE,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0001::word4) then ― ‹TE›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TE,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TE,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b1010::word4) then ― ‹TG›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TG,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TG,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0010::word4) then ― ‹TLE›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TLE,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TLE,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b1011::word4) then ― ‹TGE›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TGE,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TGE,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0011::word4) then ― ‹TL›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TL,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TL,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b1100::word4) then ― ‹TGU›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TGU,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TGU,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0100::word4) then ― ‹TLEU›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TLEU,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TLEU,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b1101::word4) then ― ‹TCC›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TCC,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TCC,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0101::word4) then ― ‹TCS›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TCS,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TCS,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b1110::word4) then ― ‹TPOS›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TPOS,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TPOS,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0110::word4) then ― ‹TNEG›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TNEG,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TNEG,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b1111::word4) then ― ‹TVC›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TVC,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TVC,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else if trap_cond = uint(0b0111::word4) then ― ‹TVS›
        if flagi = 0 then ― ‹return [i,rs1,rs2]›
          Inr (ticc_type TVS,[(Flag (word_of_int flagi)),
                   (W5 (word_of_int rs1)),
                   (W5 (word_of_int rs2))])
        else ― ‹return [i,rs1,trap_imm7]›
          Inr (ticc_type TVS,[(Flag (word_of_int flagi)),
                    (W5 (word_of_int rs1)),
                    (Imm7 (word_of_int trap_imm7))])
      else Inl [invalid_trap_cond]     
    else Inl [invalid_op3_f3_op10]
  else Inl [invalid_op_f3]
"

text ‹Read the word32 value from the Program Counter in the current state. 
        Find the instruction in the memory address of the word32 value. 
        Return a word32 value of the insturction.›
definition fetch_instruction::"('a) sparc_state 
  (Exception list + word32)"
where "fetch_instruction s  
  ― ‹pc_val› is the 32-bit memory address of the instruction.›
  let pc_val = cpu_reg_val PC s;
      psr_val = cpu_reg_val PSR s;
      s_val = get_S psr_val;
      asi = if s_val = 0 then word_of_int 8 else word_of_int 9
  in
  ― ‹Check if pc_val› is aligned to 4-byte (32-bit) boundary.›
  ― ‹That is, check if the least significant two bits of›
  ― ‹pc_val› are 0s.›
    if uint((AND) (0b00000000000000000000000000000011) pc_val) = 0 then
    ― ‹Get the 32-bit value from the address of pc_val›
    ― ‹to the address of pc_val+3›
        let (mem_result,n_s) = memory_read asi pc_val s in
        case mem_result of 
         None  Inl [fetch_instruction_error]
        |Some v  Inr v
    else Inl [fetch_instruction_error]
"

text ‹Decode the word32 value of an instruction into 
        the name of the instruction and its operands.›
definition decode_instruction::"word32  
  Exception list + instruction"
where "decode_instruction w  
  let this_op = get_op w in 
  if this_op = uint(0b01::word2) then ― ‹Instruction format 1›
    parse_instr_f1 w
  else if this_op = uint(0b00::word2) then ― ‹Instruction format 2›
    parse_instr_f2 w
  else ― ‹op = 11 0r 10›, instruction format 3›
    parse_instr_f3 w
"

text ‹Get the current window from the PSR›
definition get_curr_win::"unit  ('a,('a::len window_size)) sparc_state_monad"
where "get_curr_win _  
  do
    curr_win  gets (λs. (ucast (get_CWP (cpu_reg_val PSR s))));
    return curr_win 
  od"

text ‹Operational semantics for CALL›
definition call_instr::"instruction  ('a::len,unit) sparc_state_monad"
where "call_instr instr 
  let op_list = snd instr;
      mem_addr = ((ucast (get_operand_w30 (op_list!0)))::word32) << 2
  in
  do
    curr_win  get_curr_win();
    pc_val  gets (λs. (cpu_reg_val PC s));
    npc_val  gets (λs. (cpu_reg_val nPC s));
    write_reg pc_val curr_win (word_of_int 15);
    write_cpu npc_val PC;
    write_cpu (pc_val + mem_addr) nPC;
    return ()
  od"

text‹Evaluate icc based on the bits N, Z, V, C in PSR 
       and the type of branching instruction. 
       See Sparcv8 manual Page 178.›
definition eval_icc::"sparc_operation  word1  word1  word1  word1  int"
where
"eval_icc instr_name n_val z_val v_val c_val 
    if instr_name = bicc_type BNE then
      if z_val = 0 then 1 else 0
    else if instr_name = bicc_type BE then 
      if z_val = 1 then 1 else 0
    else if instr_name = bicc_type BG then
      if ((OR) z_val (n_val XOR v_val)) = 0 then 1 else 0
    else if instr_name = bicc_type BLE then
      if ((OR) z_val (n_val XOR v_val)) = 1 then 1 else 0
    else if instr_name = bicc_type BGE then
      if (n_val XOR v_val) = 0 then 1 else 0
    else if instr_name = bicc_type BL then
      if (n_val XOR v_val) = 1 then 1 else 0
    else if instr_name = bicc_type BGU then
      if (c_val = 0  z_val = 0) then 1 else 0
    else if instr_name = bicc_type BLEU then
      if (c_val = 1  z_val = 1) then 1 else 0
    else if instr_name = bicc_type BCC then
      if c_val = 0 then 1 else 0
    else if instr_name = bicc_type BCS then
      if c_val = 1 then 1 else 0
    else if instr_name = bicc_type BNEG then
      if n_val = 1 then 1 else 0
    else if instr_name = bicc_type BA then 1
    else if instr_name = bicc_type BN then 0
    else if instr_name = bicc_type BPOS then
      if n_val = 0 then 1 else 0
    else if instr_name = bicc_type BVC then
      if v_val = 0 then 1 else 0
    else if instr_name = bicc_type BVS then
      if v_val = 1 then 1 else 0
    else -1
"

definition branch_instr_sub1:: "sparc_operation  ('a) sparc_state  int"
where "branch_instr_sub1 instr_name s 
  let n_val = get_icc_N ((cpu_reg s) PSR);
      z_val = get_icc_Z ((cpu_reg s) PSR);
      v_val = get_icc_V ((cpu_reg s) PSR);
      c_val = get_icc_C ((cpu_reg s) PSR)
  in
  eval_icc instr_name n_val z_val v_val c_val"

text ‹Operational semantics for Branching insturctions. 
        Return exception or a bool value for annulment. 
        If the bool value is 1, then the delay instruciton 
        is not executed, otherwise the delay instruction
        is executed.›
definition branch_instr::"instruction  ('a,unit) sparc_state_monad"
where "branch_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      disp22 = get_operand_w22 (op_list!1);
      flaga = get_operand_flag (op_list!0)
  in
  do
    icc_val  gets( λs. (branch_instr_sub1 instr_name s));
    npc_val  gets (λs. (cpu_reg_val nPC s));
    pc_val  gets (λs. (cpu_reg_val PC s));
    write_cpu npc_val PC;    
    if icc_val = 1 then 
      do
        write_cpu (pc_val + (sign_ext24 (((ucast(disp22))::word24) << 2))) nPC;
        if (instr_name = bicc_type BA)  (flaga = 1) then 
          do
            set_annul True;
            return ()
          od
        else
          return ()
      od
    else ― ‹icc_val = 0›
      do
        write_cpu (npc_val + 4) nPC;
        if flaga = 1 then
          do                
            set_annul True;
            return ()
          od
        else return ()
      od
  od"

text ‹Operational semantics for NOP›
definition nop_instr::"instruction  ('a,unit) sparc_state_monad"
where "nop_instr instr  return ()"

text ‹Operational semantics for SETHI›
definition sethi_instr::"instruction  ('a::len,unit) sparc_state_monad"
where "sethi_instr instr 
  let op_list = snd instr;
      imm22 = get_operand_w22 (op_list!0); 
      rd = get_operand_w5 (op_list!1)
  in
  if rd  0 then
    do
      curr_win  get_curr_win();
      write_reg (((ucast(imm22))::word32) << 10) curr_win rd;
      return ()
    od
  else return ()
"

text ‹
  Get operand2› based on the flag i›, rs1›, rs2›, and simm13›.
  If i = 0› then operand2 = r[rs2]›,
  else operand2 = sign_ext13(simm13)›.
  op_list› should be [i,rs1,rs2,…]› or [i,rs1,simm13,…]›.
›
definition get_operand2::"inst_operand list  ('a::len) sparc_state
   virtua_address"
where "get_operand2 op_list s 
  let flagi = get_operand_flag (op_list!0);
      curr_win = ucast (get_CWP (cpu_reg_val PSR s))
  in
  if flagi = 0 then
    let rs2 = get_operand_w5 (op_list!2);
        rs2_val = user_reg_val curr_win rs2 s
    in rs2_val
  else
    let ext_simm13 = sign_ext13 (get_operand_simm13 (op_list!2)) in
    ext_simm13
"

text ‹
  Get operand2_val› based on the flag i›, rs1›, rs2›, and simm13›.
  If i = 0› then operand2_val = uint r[rs2]›,
  else operand2_val = sint sign_ext13(simm13)›.
  op_list› should be [i,rs1,rs2,…]› or [i,rs1,simm13,…]›.
›
definition get_operand2_val::"inst_operand list  ('a::len) sparc_state  int"
where "get_operand2_val op_list s 
  let flagi = get_operand_flag (op_list!0);
      curr_win = ucast (get_CWP (cpu_reg_val PSR s))
  in
  if flagi = 0 then
    let rs2 = get_operand_w5 (op_list!2);
        rs2_val = user_reg_val curr_win rs2 s
    in sint rs2_val
  else
    let ext_simm13 = sign_ext13 (get_operand_simm13 (op_list!2)) in
    sint ext_simm13
"

text ‹
  Get the address based on the flag i›, rs1›, rs2›, and simm13›.
  If i = 0› then addr = r[rs1] + r[rs2]›,
  else addr = r[rs1] + sign_ext13(simm13)›.
  op_list› should be [i,rs1,rs2,…]› or [i,rs1,simm13,…]›.
›
definition get_addr::"inst_operand list  ('a::len) sparc_state  virtua_address"
where "get_addr op_list s 
  let rs1 = get_operand_w5 (op_list!1);
      curr_win = ucast (get_CWP (cpu_reg_val PSR s));
      rs1_val = user_reg_val curr_win rs1 s;
      op2 = get_operand2 op_list s
  in
  (rs1_val + op2)
"

text ‹Operational semantics for JMPL›
definition jmpl_instr::"instruction  ('a::len,unit) sparc_state_monad"
where "jmpl_instr instr 
  let op_list = snd instr;
      rd = get_operand_w5 (op_list!3)      
  in
  do
    curr_win  get_curr_win();
    jmp_addr  gets (λs. (get_addr op_list s));
    if ((AND) jmp_addr 0b00000000000000000000000000000011)  0 then
      do
        raise_trap mem_address_not_aligned;
        return ()
      od
    else
      do
        rd_next_val  gets (λs. (if rd  0 then
                                    (cpu_reg_val PC s)
                                  else 
                                    user_reg_val curr_win rd s));
        write_reg rd_next_val curr_win rd;
        npc_val  gets (λs. (cpu_reg_val nPC s));
        write_cpu npc_val PC;
        write_cpu jmp_addr nPC;
        return ()
      od
  od"

text ‹Operational semantics for RETT›
definition rett_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "rett_instr instr 
  let op_list = snd instr in
  do
    psr_val  gets (λs. (cpu_reg_val PSR s));
    curr_win  gets (λs. (get_CWP (cpu_reg_val PSR s)));
    new_cwp  gets (λs. (word_of_int (((uint curr_win) + 1) mod NWINDOWS)));
    new_cwp_int  gets (λs. ((uint curr_win) + 1) mod NWINDOWS);
    addr  gets (λs. (get_addr op_list s));
    et_val  gets (λs. ((ucast (get_ET psr_val))::word1));
    s_val  gets (λs. ((ucast (get_S psr_val))::word1));
    ps_val  gets (λs. ((ucast (get_PS psr_val))::word1));
    wim_val  gets (λs. (cpu_reg_val WIM s));
    npc_val  gets (λs. (cpu_reg_val nPC s));
    if et_val = 1 then
      if s_val = 0 then 
        do
          raise_trap privileged_instruction;
          return ()
        od
      else
        do
          raise_trap illegal_instruction;
          return ()
        od
    else if s_val = 0 then
      do 
        write_cpu_tt (0b00000011::word8);
        set_exe_mode False;
        set_err_mode True;
        raise_trap privileged_instruction;
        fail ()
      od
    else if (get_WIM_bit (nat new_cwp_int) wim_val)  0 then
      do
        write_cpu_tt (0b00000110::word8);
        set_exe_mode False;
        set_err_mode True;
        raise_trap window_underflow;
        fail ()
      od
    else if ((AND) addr (0b00000000000000000000000000000011::word32))  0 then
      do
        write_cpu_tt (0b00000111::word8);
        set_exe_mode False;
        set_err_mode True;
        raise_trap mem_address_not_aligned;
        fail ()
      od
    else
      do
        write_cpu npc_val PC;
        write_cpu addr nPC;
        new_psr_val  gets (λs. (update_PSR_rett new_cwp 1 ps_val psr_val));
        write_cpu new_psr_val PSR;
        return ()
      od
  od"

definition save_retore_sub1 :: "word32  word5  word5  ('a::len,unit) sparc_state_monad"
where "save_retore_sub1 result new_cwp rd 
  do
  psr_val  gets (λs. (cpu_reg_val PSR s));
  new_psr_val  gets (λs. (update_CWP new_cwp psr_val));
  write_cpu new_psr_val PSR; ― ‹Change CWP› to the new window value.›
  write_reg result (ucast new_cwp) rd; ― ‹Write result in rd› of the new window.›
  return ()
  od"

text ‹Operational semantics for SAVE and RESTORE.›
definition save_restore_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "save_restore_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rd = get_operand_w5 (op_list!3)
  in
  do
    psr_val  gets (λs. (cpu_reg_val PSR s));
    curr_win  get_curr_win();
    wim_val  gets (λs. (cpu_reg_val WIM s));
    if instr_name = ctrl_type SAVE then 
      do
        new_cwp  gets (λs. ((word_of_int (((uint curr_win) - 1) mod NWINDOWS)))::word5);
        if (get_WIM_bit (unat new_cwp) wim_val)  0 then 
          do
            raise_trap window_overflow;
            return ()
          od
        else
          do
            result  gets (λs. (get_addr op_list s)); ― ‹operands are from the old window.›
            save_retore_sub1 result new_cwp rd
          od
      od
    else ― ‹instr_name = RESTORE›
      do
        new_cwp  gets (λs. ((word_of_int (((uint curr_win) + 1) mod NWINDOWS)))::word5);
        if (get_WIM_bit (unat new_cwp) wim_val)  0 then 
          do
            raise_trap window_underflow;
            return ()
          od
        else
          do
            result  gets (λs. (get_addr op_list s)); ― ‹operands are from the old window.›
            save_retore_sub1 result new_cwp rd
          od
      od
  od"

definition flush_cache_line :: "word32  ('a,unit) sparc_state_monad"
where "flush_cache_line  undefined"

definition flush_Ibuf_and_pipeline :: "word32  ('a,unit) sparc_state_monad"
where "flush_Ibuf_and_pipeline  undefined"

text ‹Operational semantics for FLUSH. 
        Flush the all the caches.›
definition flush_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "flush_instr instr 
  let op_list = snd instr in
  do
    addr  gets (λs. (get_addr op_list s));
    modify (λs. (flush_cache_all s));
    ⌦‹flush_cache_line(addr);›
    ⌦‹flush_Ibuf_and_pipeline(addr);›
    return ()
  od"

text ‹Operational semantics for read state register instructions. 
        We do not consider RDASR here.›
definition read_state_reg_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "read_state_reg_instr instr  
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!0);
      rd = get_operand_w5 (op_list!1)
  in
  do  
    curr_win  get_curr_win();
    psr_val  gets (λs. (cpu_reg_val PSR s));
    s_val  gets (λs. (get_S psr_val));
    if (instr_name  {sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR}  
        (instr_name = sreg_type RDASR  privileged_ASR rs1)) 
        ((ucast s_val)::word1) = 0 then
      do
        raise_trap privileged_instruction;
        return ()
      od
    else if illegal_instruction_ASR rs1 then 
      do
        raise_trap illegal_instruction;
        return ()
      od
    else if rd  0 then
      if instr_name = sreg_type RDY then
        do
          y_val  gets (λs. (cpu_reg_val Y s));
          write_reg y_val curr_win rd;
          return ()
        od
      else if instr_name = sreg_type RDASR then
        do
          asr_val  gets (λs. (cpu_reg_val (ASR rs1) s));
          write_reg asr_val curr_win rd;
          return ()
        od
      else if instr_name = sreg_type RDPSR then
        do
          write_reg psr_val curr_win rd;
          return ()
        od
      else if instr_name = sreg_type RDWIM then
        do
          wim_val  gets (λs. (cpu_reg_val WIM s));
          write_reg wim_val curr_win rd;
          return ()
        od
      else ― ‹Must be RDTBR›.›
        do
          tbr_val  gets (λs. (cpu_reg_val TBR s));
          write_reg tbr_val curr_win rd;
          return ()
        od      
    else return ()  
  od"

text ‹Operational semantics for write state register instructions. 
        We do not consider WRASR here.›
definition write_state_reg_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "write_state_reg_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    curr_win  get_curr_win();
    psr_val  gets (λs. (cpu_reg_val PSR s));
    s_val  gets (λs. (get_S psr_val));
    op2  gets (λs. (get_operand2 op_list s));
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    result  gets (λs. ((XOR) rs1_val op2));
    if instr_name = sreg_type WRY then
      do
        modify (λs. (delayed_pool_add (DELAYNUM, result, Y) s));
        return ()
      od 
    else if instr_name = sreg_type WRASR then
        if privileged_ASR rd  s_val = 0 then
          do
            raise_trap privileged_instruction;
            return ()
          od
        else if illegal_instruction_ASR rd then
          do
            raise_trap illegal_instruction;
            return ()
          od
        else 
          do
            modify (λs. (delayed_pool_add (DELAYNUM, result, (ASR rd)) s));
            return ()
          od
    else if instr_name = sreg_type WRPSR then
      if s_val = 0 then
        do
          raise_trap privileged_instruction;
          return ()
        od
      else if (uint ((ucast result)::word5))  NWINDOWS then
        do
          raise_trap illegal_instruction;
          return ()
        od
      else 
        do ― ‹ET› and PIL› appear to be written IMMEDIATELY w.r.t. interrupts.›
          pil_val  gets (λs. (get_PIL result));
          et_val  gets (λs. (get_ET result));
          new_psr_val  gets (λs. (update_PSR_et_pil et_val pil_val psr_val));
          write_cpu new_psr_val PSR;
          modify (λs. (delayed_pool_add (DELAYNUM, result, PSR) s));
          return ()
        od
    else if instr_name = sreg_type WRWIM then
      if s_val = 0 then
        do
          raise_trap privileged_instruction;
          return ()
        od
      else 
        do ― ‹Don't write bits corresponding to non-existent windows.›
          result_f  gets (λs. ((result << nat (32 - NWINDOWS)) >> nat (32 - NWINDOWS)));
          modify (λs. (delayed_pool_add (DELAYNUM, result_f, WIM) s));
          return ()
        od
    else  ― ‹Must be WRTBR›
      if s_val = 0 then
        do
          raise_trap privileged_instruction;
          return ()
        od
      else 
        do ― ‹Only write the bits <31:12>› of the result to TBR›.›
          tbr_val  gets (λs. (cpu_reg_val TBR s));
          tbr_val_11_0  gets (λs. ((AND) tbr_val 0b00000000000000000000111111111111));
          result_tmp  gets (λs. ((AND) result 0b11111111111111111111000000000000));
          result_f  gets (λs. ((OR) tbr_val_11_0 result_tmp));
          modify (λs. (delayed_pool_add (DELAYNUM, result_f, TBR) s));
          return ()
        od
  od"

definition logical_result :: "sparc_operation  word32  word32  word32"
where "logical_result instr_name rs1_val operand2 
  if (instr_name = logic_type ANDs)  
                            (instr_name = logic_type ANDcc) then
                          (AND) rs1_val operand2     
                         else if (instr_name = logic_type ANDN)  
                                 (instr_name = logic_type ANDNcc) then
                          (AND) rs1_val (NOT operand2)
                         else if (instr_name = logic_type ORs)  
                                 (instr_name = logic_type ORcc) then
                          (OR) rs1_val operand2
                         else if instr_name  {logic_type ORN,logic_type ORNcc} then 
                          (OR) rs1_val (NOT operand2)
                         else if instr_name  {logic_type XORs,logic_type XORcc} then 
                          (XOR) rs1_val operand2
                         else ― ‹Must be XNOR› or XNORcc›
                          (XOR) rs1_val (NOT operand2)
"

definition logical_new_psr_val :: "word32  ('a) sparc_state  word32"
where "logical_new_psr_val result s 
  let psr_val = cpu_reg_val PSR s;
        n_val = (ucast (result >> 31))::word1;
        z_val = if (result = 0) then 1 else 0;
        v_val = 0;
        c_val = 0
  in
  update_PSR_icc n_val z_val v_val c_val psr_val
"

definition logical_instr_sub1 :: "sparc_operation  word32  
  ('a::len,unit) sparc_state_monad"
where
"logical_instr_sub1 instr_name result 
  if instr_name  {logic_type ANDcc,logic_type ANDNcc,logic_type ORcc,
      logic_type ORNcc,logic_type XORcc,logic_type XNORcc} then
      do
        new_psr_val  gets (λs. (logical_new_psr_val result s));
        write_cpu new_psr_val PSR;
        return ()
      od
    else return () 
"

text ‹Operational semantics for logical instructions.›
definition logical_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "logical_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    operand2  gets (λs. (get_operand2 op_list s));
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    rd_val  gets (λs. (user_reg_val curr_win rd s));
    result  gets (λs. (logical_result instr_name rs1_val operand2));
    new_rd_val  gets (λs. (if rd  0 then result else rd_val));
    write_reg new_rd_val curr_win rd;
    logical_instr_sub1 instr_name result
  od"

text ‹Operational semantics for shift instructions.›
definition shift_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "shift_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      flagi = get_operand_flag (op_list!0);
      rs1 = get_operand_w5 (op_list!1);
      rs2_shcnt = get_operand_w5 (op_list!2);
      rd = get_operand_w5 (op_list!3)
  in
  do
    curr_win  get_curr_win();
    shift_count  gets (λs. (if flagi = 0 then 
                                ucast (user_reg_val curr_win rs2_shcnt s) 
                              else rs2_shcnt));
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    if (instr_name = shift_type SLL)  (rd  0) then 
      do
        rd_val  gets (λs. (rs1_val << (unat shift_count)));
        write_reg rd_val curr_win rd;
        return ()
      od
    else if (instr_name = shift_type SRL)  (rd  0) then
      do
        rd_val  gets (λs. (rs1_val >> (unat shift_count)));
        write_reg rd_val curr_win rd;
        return ()
      od
    else if (instr_name = shift_type SRA)  (rd  0) then
      do
        rd_val  gets (λs. (rs1_val >>> (unat shift_count)));
        write_reg rd_val curr_win rd;
        return ()
      od
    else return ()
  od"

definition add_instr_sub1 :: "sparc_operation  word32  word32  word32
   ('a::len,unit) sparc_state_monad"
where "add_instr_sub1 instr_name result rs1_val operand2 
  if instr_name  {arith_type ADDcc,arith_type ADDXcc} then
      do
        psr_val  gets (λs. (cpu_reg_val PSR s));
        result_31  gets (λs. ((ucast (result >> 31))::word1));
        rs1_val_31  gets (λs. ((ucast (rs1_val >> 31))::word1));
        operand2_31  gets (λs. ((ucast (operand2 >> 31))::word1));
        new_n_val  gets (λs. (result_31));
        new_z_val  gets (λs. (if result = 0 then 1::word1 else 0::word1));
        new_v_val  gets (λs. ((OR) ((AND) rs1_val_31 
                                              ((AND) operand2_31 
                                                      (NOT result_31))) 
                                      ((AND) (NOT rs1_val_31) 
                                              ((AND) (NOT operand2_31) 
                                                      result_31))));
        new_c_val  gets (λs. ((OR) ((AND) rs1_val_31 
                                              operand2_31) 
                                      ((AND) (NOT result_31) 
                                              ((OR) rs1_val_31 
                                                     operand2_31))));
        new_psr_val  gets (λs. (update_PSR_icc new_n_val 
                                                 new_z_val 
                                                 new_v_val 
                                                 new_c_val psr_val));
        write_cpu new_psr_val PSR;
        return ()
      od
    else return ()
"

text ‹Operational semantics for add instructions. 
        These include ADD, ADDcc, ADDX.›
definition add_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "add_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    operand2  gets (λs. (get_operand2 op_list s));
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    psr_val  gets (λs. (cpu_reg_val PSR s));
    c_val  gets (λs. (get_icc_C psr_val));
    result  gets (λs. (if (instr_name = arith_type ADD)  
                            (instr_name = arith_type ADDcc) then
                          rs1_val + operand2
                         else ― ‹Must be ADDX› or ADDXcc›
                          rs1_val + operand2 + (ucast c_val)));
    rd_val  gets (λs. (user_reg_val curr_win rd s));
    new_rd_val  gets (λs. (if rd  0 then result else rd_val));
    write_reg new_rd_val curr_win rd;
    add_instr_sub1 instr_name result rs1_val operand2
  od"

definition sub_instr_sub1 :: "sparc_operation  word32  word32  word32
   ('a::len,unit) sparc_state_monad"
where "sub_instr_sub1 instr_name result rs1_val operand2 
  if instr_name  {arith_type SUBcc,arith_type SUBXcc} then
      do
        psr_val  gets (λs. (cpu_reg_val PSR s));
        result_31  gets (λs. ((ucast (result >> 31))::word1));
        rs1_val_31  gets (λs. ((ucast (rs1_val >> 31))::word1));
        operand2_31  gets (λs. ((ucast (operand2 >> 31))::word1));
        new_n_val  gets (λs. (result_31));
        new_z_val  gets (λs. (if result = 0 then 1::word1 else 0::word1));
        new_v_val  gets (λs. ((OR) ((AND) rs1_val_31 
                                              ((AND) (NOT operand2_31) 
                                                      (NOT result_31))) 
                                      ((AND) (NOT rs1_val_31) 
                                              ((AND) operand2_31 
                                                      result_31))));
        new_c_val  gets (λs. ((OR) ((AND) (NOT rs1_val_31) 
                                              operand2_31) 
                                      ((AND) result_31 
                                              ((OR) (NOT rs1_val_31) 
                                                     operand2_31))));
        new_psr_val  gets (λs. (update_PSR_icc new_n_val 
                                                 new_z_val 
                                                 new_v_val 
                                                 new_c_val psr_val));
        write_cpu new_psr_val PSR;
        return ()
      od
    else return ()
"

text ‹Operational semantics for subtract instructions. 
        These include SUB, SUBcc, SUBX.›
definition sub_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "sub_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    operand2  gets (λs. (get_operand2 op_list s));
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    psr_val  gets (λs. (cpu_reg_val PSR s));
    c_val  gets (λs. (get_icc_C psr_val));
    result  gets (λs. (if (instr_name = arith_type SUB)  
                            (instr_name = arith_type SUBcc) then
                          rs1_val - operand2
                         else ― ‹Must be SUBX› or SUBXcc›
                          rs1_val - operand2 - (ucast c_val)));
    rd_val  gets (λs. (user_reg_val curr_win rd s));
    new_rd_val  gets (λs. (if rd  0 then result else rd_val));
    write_reg new_rd_val curr_win rd;
    sub_instr_sub1 instr_name result rs1_val operand2
  od"

definition mul_instr_sub1 :: "sparc_operation  word32  
  ('a::len,unit) sparc_state_monad"
where "mul_instr_sub1 instr_name result 
  if instr_name  {arith_type SMULcc,arith_type UMULcc} then
      do
        psr_val  gets (λs. (cpu_reg_val PSR s));
        new_n_val  gets (λs. ((ucast (result >> 31))::word1));
        new_z_val  gets (λs. (if result = 0 then 1 else 0));
        new_v_val  gets (λs. 0);
        new_c_val  gets (λs. 0);
        new_psr_val  gets (λs. (update_PSR_icc new_n_val 
                                                 new_z_val 
                                                 new_v_val 
                                                 new_c_val psr_val));
        write_cpu new_psr_val PSR;
        return ()
      od
    else return ()
"

text ‹Operational semantics for multiply instructions.›
definition mul_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "mul_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    operand2  gets (λs. (get_operand2 op_list s));
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    psr_val  gets (λs. (cpu_reg_val PSR s));
    result0  gets (λs. (if instr_name  {arith_type UMUL,arith_type UMULcc} then 
                            (word_of_int ((uint rs1_val) * 
                                          (uint operand2)))::word64
                          else ― ‹Must be SMUL› or SMULcc›
                            (word_of_int ((sint rs1_val) * 
                                          (sint operand2)))::word64));
    ― ‹whether to use ucast› or scast› does not matter below.›
    y_val  gets (λs. ((ucast (result0 >> 32))::word32));
    write_cpu y_val Y;
    result  gets (λs. ((ucast result0)::word32));
    rd_val  gets (λs. (user_reg_val curr_win rd s));
    new_rd_val  gets (λs. (if rd  0 then result else rd_val));
    write_reg new_rd_val curr_win rd;
    mul_instr_sub1 instr_name result
  od"

definition div_comp_temp_64bit :: "instruction  word64  
  virtua_address  word64"
where "div_comp_temp_64bit i y_rs1 operand2  
  if ((fst i) = arith_type UDIV)  ((fst i) = arith_type UDIVcc) then 
    (word_of_int ((uint y_rs1) div (uint operand2)))::word64
  else ― ‹Must be SDIV› or SDIVcc›.›
    ― ‹Due to Isabelle's rounding method is not nearest to zero,›
    ― ‹we have to implement division in a different way.›
    let sop1 = sint y_rs1;
        sop2 = sint operand2;
        pop1 = abs sop1;
        pop2 = abs sop2
    in
    if sop1 > 0  sop2 > 0 then 
      (word_of_int (sop1 div sop2))
    else if sop1 > 0  sop2 < 0 then
      (word_of_int (- (sop1 div pop2)))
    else if sop1 < 0  sop2 > 0 then
      (word_of_int (- (pop1 div sop2)))
    else ― ‹sop1 < 0 ∧ sop2 < 0›
      (word_of_int (pop1 div pop2))"

definition div_comp_temp_V :: "instruction  word32  word33  word1"
where "div_comp_temp_V i w32 w33  
  if ((fst i) = arith_type UDIV)  ((fst i) = arith_type UDIVcc) then
    if w32 = 0 then 0 else 1
  else ― ‹Must be SDIV› or SDIVcc›.›
    if (w33 = 0)  (w33 = (0b111111111111111111111111111111111::word33)) 
    then 0 else 1"

definition div_comp_result :: "instruction  word1  word64  word32"
where "div_comp_result i temp_V temp_64bit 
  if temp_V = 1 then
    if ((fst i) = arith_type UDIV)  ((fst i) = arith_type UDIVcc) then
      (0b11111111111111111111111111111111::word32)
    else if (fst i)  {arith_type SDIV,arith_type SDIVcc} then  
      if temp_64bit > 0 then 
        (0b01111111111111111111111111111111::word32)
      else ((word_of_int (0 - (uint (0b10000000000000000000000000000000::word32))))::word32)
    else ((ucast temp_64bit)::word32)
  else ((ucast temp_64bit)::word32)"

definition div_write_new_val :: "instruction  word32  word1  
  ('a::len,unit) sparc_state_monad"
where "div_write_new_val i result temp_V 
  if (fst i)  {arith_type UDIVcc,arith_type SDIVcc} then
  do
    psr_val  gets (λs. (cpu_reg_val PSR s));
    new_n_val  gets (λs. ((ucast (result >> 31))::word1));
    new_z_val  gets (λs. (if result = 0 then 1 else 0));
    new_v_val  gets (λs. temp_V);
    new_c_val  gets (λs. 0);
    new_psr_val  gets (λs. (update_PSR_icc new_n_val 
                                             new_z_val 
                                             new_v_val 
                                             new_c_val psr_val));
    write_cpu new_psr_val PSR;
    return ()
  od
  else return ()"

definition div_comp :: "instruction  word5  word5  virtua_address 
  ('a::len,unit) sparc_state_monad"
where "div_comp instr rs1 rd operand2 
  do
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    
    y_val  gets (λs. (cpu_reg_val Y s));
    y_rs1  gets (λs. ((word_cat y_val rs1_val)::word64));
    temp_64bit  gets (λs. (div_comp_temp_64bit instr y_rs1 operand2));
    ⌦‹result ←  gets (λs. ((ucast temp_64bit)::word32));›
    temp_high32  gets (λs. ((ucast (temp_64bit >> 32))::word32));
    temp_high33  gets (λs. ((ucast (temp_64bit >> 31))::word33));
    temp_V  gets (λs. (div_comp_temp_V instr temp_high32 temp_high33));
    result  gets (λs. (div_comp_result instr temp_V temp_64bit));
    rd_val  gets (λs. (user_reg_val curr_win rd s));
    new_rd_val  gets (λs. (if rd  0 then result else rd_val));
    write_reg new_rd_val curr_win rd;
    div_write_new_val instr result temp_V 
  od"

text ‹Operational semantics for divide instructions.›
definition div_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "div_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    operand2  gets (λs. (get_operand2 op_list s));
    if (uint operand2) = 0 then 
      do
        raise_trap division_by_zero;
        return ()
      od
    else
      div_comp instr rs1 rd operand2
  od"

definition ld_word0 :: "instruction  word32  virtua_address   word32"
where "ld_word0 instr data_word address 
  if (fst instr)  {load_store_type LDSB,load_store_type LDUB,
    load_store_type LDUBA,load_store_type LDSBA} then                                     
    let byte = if (uint ((ucast address)::word2)) = 0 then
                 (ucast (data_word >> 24))::word8
               else if (uint ((ucast address)::word2)) = 1 then
                 (ucast (data_word >> 16))::word8
               else if (uint ((ucast address)::word2)) = 2 then
                 (ucast (data_word >> 8))::word8
               else ― ‹Must be 3.›
                 (ucast data_word)::word8
    in
    if (fst instr) = load_store_type LDSB  (fst instr) = load_store_type LDSBA then
      sign_ext8 byte
    else 
      zero_ext8 byte
  else if (fst instr) = load_store_type LDUH  (fst instr) = load_store_type LDSH  
          (fst instr) = load_store_type LDSHA  (fst instr) = load_store_type LDUHA
       then  
    let halfword = if (uint ((ucast address)::word2)) = 0 then
                     (ucast (data_word >> 16))::word16
                   else ― ‹Must be 2.›
                     (ucast data_word)::word16
    in
    if (fst instr) = load_store_type LDSH  (fst instr) = load_store_type LDSHA then
      sign_ext16 halfword
    else
      zero_ext16 halfword
  else ― ‹Must be LDD›
    data_word
"

definition ld_asi :: "instruction  word1  asi_type"
where "ld_asi instr s_val 
  if (fst instr)  {load_store_type LDD,load_store_type LD,load_store_type LDUH,
    load_store_type LDSB,load_store_type LDUB,load_store_type LDSH} then
    if s_val = 0 then (word_of_int 10)::asi_type
    else (word_of_int 11)::asi_type
  else ― ‹Must be LDA›, LDUBA›, LDSBA›, LDSHA›, LDUHA›, or LDDA›.›
    get_operand_asi ((snd instr)!3)
"

definition load_sub2 :: "virtua_address  asi_type  word5  
  ('a::len) window_size  word32  ('a,unit) sparc_state_monad"
where "load_sub2 address asi rd curr_win word0 
  do
    write_reg word0 curr_win ((AND) rd 0b11110);
    (result1,new_state1)  gets (λs. (memory_read asi (address + 4) s));
    if result1 = None then
    do
      raise_trap data_access_exception;
      return ()
    od
    else
    do
      word1  gets (λs. (case result1 of Some v  v));
      modify (λs. (new_state1));
      write_reg word1 curr_win ((OR) rd 1);
      return ()                                       
    od
  od"

definition load_sub3 :: "instruction  ('a::len) window_size 
  word5  asi_type  virtua_address 
  ('a::len,unit) sparc_state_monad"
where "load_sub3 instr curr_win rd asi address 
  do
    (result,new_state)  gets (λs. (memory_read asi address s));
    if result = None then
    do
      raise_trap data_access_exception;
      return ()
    od
    else
    do
      data_word  gets (λs. (case result of Some v  v));
      modify (λs. (new_state));
      word0  gets (λs. (ld_word0 instr data_word address));
      if rd  0  (fst instr)  {load_store_type LD,load_store_type LDA,
        load_store_type LDUH,load_store_type LDSB,load_store_type LDUB,
        load_store_type LDUBA,load_store_type LDSH,load_store_type LDSHA,
        load_store_type LDUHA,load_store_type LDSBA} then
      do
        write_reg word0 curr_win rd;
        return ()
      od
      else ― ‹Must be LDD› or LDDA›
        load_sub2 address asi rd curr_win word0
    od
  od"

definition load_sub1 :: "instruction  word5  word1 
  ('a::len,unit) sparc_state_monad"
where "load_sub1 instr rd s_val 
  do
    curr_win  get_curr_win();
    address  gets (λs. (get_addr (snd instr) s));
    asi  gets (λs. (ld_asi instr s_val));
    if (((fst instr) = load_store_type LDD  (fst instr) = load_store_type LDDA) 
        ((ucast address)::word3)  0) 
          ((fst instr)  {load_store_type LD,load_store_type LDA} 
             ((ucast address)::word2)  0)
          (((fst instr) = load_store_type LDUH  (fst instr) = load_store_type LDUHA 
              (fst instr) = load_store_type LDSH  (fst instr) = load_store_type LDSHA) 
             ((ucast address)::word1)  0)
    then
    do
      raise_trap mem_address_not_aligned;
      return ()
    od
    else
      load_sub3 instr curr_win rd asi address
  od"

text ‹Operational semantics for Load instructions.›
definition load_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "load_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      flagi = get_operand_flag (op_list!0);
      rd = if instr_name  {load_store_type LDUBA,load_store_type LDA,
        load_store_type LDSBA,load_store_type LDSHA,
        load_store_type LDSHA,load_store_type LDDA} then ― ‹rd› is member 4›
            get_operand_w5 (op_list!4)
           else ― ‹rd› is member 3›
            get_operand_w5 (op_list!3)
  in  
  do
    psr_val  gets (λs. (cpu_reg_val PSR s));
    s_val  gets (λs. (get_S psr_val));
    if instr_name  {load_store_type LDA,load_store_type LDUBA,
      load_store_type LDSBA,load_store_type LDSHA,
      load_store_type LDUHA,load_store_type LDDA}  s_val = 0 then 
      do
        raise_trap privileged_instruction;
        return ()
      od
    else if instr_name  {load_store_type LDA,load_store_type LDUBA,
      load_store_type LDSBA,load_store_type LDSHA,load_store_type LDUHA,
      load_store_type LDDA}  flagi = 1 then
      do
        raise_trap illegal_instruction;
        return ()
      od
    else
      load_sub1 instr rd s_val        
  od"

definition st_asi :: "instruction  word1  asi_type"
where "st_asi instr s_val 
  if (fst instr)  {load_store_type STD,load_store_type ST,
    load_store_type STH,load_store_type STB} then
    if s_val = 0 then (word_of_int 10)::asi_type
    else (word_of_int 11)::asi_type
  else ― ‹Must be STA›, STBA›, STHA›, STDA›.›
    get_operand_asi ((snd instr)!3)
"

definition st_byte_mask :: "instruction  virtua_address  word4"
where "st_byte_mask instr address 
  if (fst instr)  {load_store_type STD,load_store_type ST,
    load_store_type STA,load_store_type STDA} then 
    (0b1111::word4)
  else if (fst instr)  {load_store_type STH,load_store_type STHA} then
    if ((ucast address)::word2) = 0 then
      (0b1100::word4)
    else ― ‹Must be 2.›
      (0b0011::word4)
  else ― ‹Must be STB› or STBA›.›
    if ((ucast address)::word2) = 0 then 
      (0b1000::word4)
    else if ((ucast address)::word2) = 1 then 
      (0b0100::word4)
    else if ((ucast address)::word2) = 2 then 
      (0b0010::word4)
    else ― ‹Must be 3.›
      (0b0001::word4)
"

definition st_data0 :: "instruction  ('a::len) window_size  
  word5  virtua_address  ('a) sparc_state  reg_type"
where "st_data0 instr curr_win rd address s 
  if (fst instr)  {load_store_type STD,load_store_type STDA} then 
    user_reg_val curr_win ((AND) rd 0b11110) s
  else if (fst instr)  {load_store_type ST,load_store_type STA} then 
    user_reg_val curr_win rd s
  else if (fst instr)  {load_store_type STH,load_store_type STHA} then
    if ((ucast address)::word2) = 0 then 
      (user_reg_val curr_win rd s) << 16
    else ― ‹Must be 2.›
      user_reg_val curr_win rd s
  else ― ‹Must be STB› or STBA›.›
    if ((ucast address)::word2) = 0 then 
       (user_reg_val curr_win rd s) << 24
    else if ((ucast address)::word2) = 1 then
       (user_reg_val curr_win rd s) << 16
    else if ((ucast address)::word2) = 2 then
        (user_reg_val curr_win rd s) << 8
    else ― ‹Must be 3.›
        user_reg_val curr_win rd s
"

definition store_sub2 :: "instruction  ('a::len) window_size 
  word5  asi_type  virtua_address  
  ('a::len,unit) sparc_state_monad"
where "store_sub2 instr curr_win rd asi address 
  do
    byte_mask  gets (λs. (st_byte_mask instr address));
    data0  gets (λs. (st_data0 instr curr_win rd address s));
    result0  gets (λs. (memory_write asi address byte_mask data0 s));
    if result0 = None then
    do
      raise_trap data_access_exception;
      return ()
    od
    else 
    do
      new_state  gets (λs. (case result0 of Some v  v));
      modify (λs. (new_state));
      if (fst instr)  {load_store_type STD,load_store_type STDA} then  
      do
        data1  gets (λs. (user_reg_val curr_win ((OR) rd 0b00001) s));
        result1  gets (λs. (memory_write asi (address + 4) (0b1111::word4) data1 s));
        if result1 = None then
        do
          raise_trap data_access_exception;
          return ()
        od
        else 
          do
          new_state1  gets (λs. (case result1 of Some v  v));
          modify (λs. (new_state1));
          return ()
          od
      od
      else
        return ()
    od
  od"

definition store_sub1 :: "instruction  word5  word1  
  ('a::len,unit) sparc_state_monad"
where "store_sub1 instr rd s_val 
  do
    curr_win  get_curr_win();
    address  gets (λs. (get_addr (snd instr) s));
    asi  gets (λs. (st_asi instr s_val));
    ― ‹The following code is intentionally long to match the definitions in SPARCv8.›
    if ((fst instr) = load_store_type STH  (fst instr) = load_store_type STHA) 
        ((ucast address)::word1)  0 then
    do  
      raise_trap mem_address_not_aligned;
      return ()
    od
    else if (fst instr)  {load_store_type ST,load_store_type STA} 
             ((ucast address)::word2)  0 then
    do  
      raise_trap mem_address_not_aligned;
      return ()
    od
    else if (fst instr)  {load_store_type STD,load_store_type STDA} 
             ((ucast address)::word3)  0 then
    do  
      raise_trap mem_address_not_aligned;
      return ()
    od
    else 
      store_sub2 instr curr_win rd asi address
  od"

text ‹Operational semantics for Store instructions.›
definition store_instr :: "instruction  
  ('a::len,unit) sparc_state_monad"
where "store_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      flagi = get_operand_flag (op_list!0);
      rd = if instr_name  {load_store_type STA,load_store_type STBA,
            load_store_type STHA,load_store_type STDA} then ― ‹rd› is member 4›
            get_operand_w5 (op_list!4)
           else ― ‹rd› is member 3›
            get_operand_w5 (op_list!3)
  in
  do   
    psr_val  gets (λs. (cpu_reg_val PSR s));
    s_val  gets (λs. (get_S psr_val));
    if instr_name  {load_store_type STA,load_store_type STDA,
      load_store_type STHA,load_store_type STBA}  s_val = 0 then
      do
        raise_trap privileged_instruction;
        return ()
      od
    else if instr_name  {load_store_type STA,load_store_type STDA,
      load_store_type STHA,load_store_type STBA}  flagi = 1 then
      do
        raise_trap illegal_instruction;
        return ()
      od
    else
      store_sub1 instr rd s_val
  od"

text ‹The instructions below are not used by Xtratum and they are 
  not tested.›

definition ldst_asi :: "instruction  word1  asi_type"
where "ldst_asi instr s_val 
  if (fst instr)  {load_store_type LDSTUB} then
    if s_val = 0 then (word_of_int 10)::asi_type
    else (word_of_int 11)::asi_type
  else ― ‹Must be LDSTUBA›.›
    get_operand_asi ((snd instr)!3)
"

definition ldst_word0 :: "instruction  word32  virtua_address   word32"
where "ldst_word0 instr data_word address                                  
  let byte = if (uint ((ucast address)::word2)) = 0 then
                 (ucast (data_word >> 24))::word8
               else if (uint ((ucast address)::word2)) = 1 then
                 (ucast (data_word >> 16))::word8
               else if (uint ((ucast address)::word2)) = 2 then
                 (ucast (data_word >> 8))::word8
               else ― ‹Must be 3.›
                 (ucast data_word)::word8
  in
  zero_ext8 byte
"

definition ldst_byte_mask :: "instruction  virtua_address  word4"
where "ldst_byte_mask instr address 
    if ((ucast address)::word2) = 0 then 
      (0b1000::word4)
    else if ((ucast address)::word2) = 1 then 
      (0b0100::word4)
    else if ((ucast address)::word2) = 2 then 
      (0b0010::word4)
    else ― ‹Must be 3.›
      (0b0001::word4)
"

definition load_store_sub1 :: "instruction  word5  word1 
  ('a::len,unit) sparc_state_monad"
where "load_store_sub1 instr rd s_val 
  do
    curr_win  get_curr_win();
    address  gets (λs. (get_addr (snd instr) s));
    asi  gets (λs. (ldst_asi instr s_val));
    ― ‹wait for locks to be lifted.›
    ― ‹an implementation actually need only block when another LDSTUB› or SWAP›
    ― ‹is pending on the same byte in memory as the one addressed by this LDSTUB›
    ― ‹Should wait when block_type = 1 ∨ block_word = 1›
    ― ‹until another processes write both to be 0.›
    ― ‹We implement this as setting pc› as npc› when the instruction›
    ― ‹is blocked. This way, in the next iteration, we will still execution›
    ― ‹the current instruction.›
    block_byte  gets (λs. (pb_block_ldst_byte_val address s));
    block_word  gets (λs. (pb_block_ldst_word_val address s));
    if block_byte  block_word then 
    do
      pc_val  gets (λs. (cpu_reg_val PC s));
      write_cpu pc_val nPC;
      return ()
    od  
    else 
    do
      modify (λs. (pb_block_ldst_byte_mod address True s));
      (result,new_state)  gets (λs. (memory_read asi address s));
      if result = None then
      do
        raise_trap data_access_exception;
        return ()
      od
      else
      do
        data_word  gets (λs. (case result of Some v  v));
        modify (λs. (new_state));
        byte_mask  gets (λs. (ldst_byte_mask instr address));
        data0  gets (λs. (0b11111111111111111111111111111111::word32));
        result0  gets (λs. (memory_write asi address byte_mask data0 s));  
        modify (λs. (pb_block_ldst_byte_mod address False s));
        if result0 = None then
        do
          raise_trap data_access_exception;
          return ()
        od
        else
        do
          new_state1  gets (λs. (case result0 of Some v  v));
          modify (λs. (new_state1));
          word0  gets (λs. (ldst_word0 instr data_word address));
          if rd  0 then
          do
            write_reg word0 curr_win rd;
            return ()
          od
          else 
            return ()
        od
      od
    od
  od"

text ‹Operational semantics for atomic load-store.›
definition load_store_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "load_store_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      flagi = get_operand_flag (op_list!0);
      rd = if instr_name  {load_store_type LDSTUBA} then ― ‹rd› is member 4›
            get_operand_w5 (op_list!4)
           else ― ‹rd› is member 3›
            get_operand_w5 (op_list!3)
  in
  do
    psr_val  gets (λs. (cpu_reg_val PSR s));
    s_val  gets (λs. (get_S psr_val));
    if instr_name  {load_store_type LDSTUBA}  s_val = 0 then 
      do
        raise_trap privileged_instruction;
        return ()
      od
    else if instr_name  {load_store_type LDSTUBA}  flagi = 1 then
      do
        raise_trap illegal_instruction;
        return ()
      od
    else
      load_store_sub1 instr rd s_val
  od"

definition swap_sub1 :: "instruction  word5  word1 
  ('a::len,unit) sparc_state_monad"
where "swap_sub1 instr rd s_val 
  do
    curr_win  get_curr_win();
    address  gets (λs. (get_addr (snd instr) s));
    asi  gets (λs. (ldst_asi instr s_val));    
    temp  gets (λs. (user_reg_val curr_win rd s));
    ― ‹wait for locks to be lifted.›
    ― ‹an implementation actually need only block when another LDSTUB› or SWAP›
    ― ‹is pending on the same byte in memory as the one addressed by this LDSTUB›
    ― ‹Should wait when block_type = 1 ∨ block_word = 1›
    ― ‹until another processes write both to be 0.›
    ― ‹We implement this as setting pc› as npc› when the instruction›
    ― ‹is blocked. This way, in the next iteration, we will still execution›
    ― ‹the current instruction.›
    block_byte  gets (λs. (pb_block_ldst_byte_val address s));
    block_word  gets (λs. (pb_block_ldst_word_val address s));
    if block_byte  block_word then 
    do
      pc_val  gets (λs. (cpu_reg_val PC s));
      write_cpu pc_val nPC;
      return ()
    od  
    else 
    do  
      modify (λs. (pb_block_ldst_word_mod address True s));
      (result,new_state)  gets (λs. (memory_read asi address s));
      if result = None then
      do
        raise_trap data_access_exception;
        return ()
      od
      else
      do
        word  gets (λs. (case result of Some v  v));
        modify (λs. (new_state));
        byte_mask  gets (λs. (0b1111::word4));
        result0  gets (λs. (memory_write asi address byte_mask temp s)); 
        modify (λs. (pb_block_ldst_word_mod address False s));
        if result0 = None then
        do
          raise_trap data_access_exception;
          return ()
        od
        else
        do
          new_state1  gets (λs. (case result0 of Some v  v));
          modify (λs. (new_state1));
          if rd  0 then
          do
            write_reg word curr_win rd;
            return ()
          od
          else 
            return ()
        od
      od
    od
  od"

text ‹Operational semantics for swap.›
definition swap_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "swap_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      flagi = get_operand_flag (op_list!0);
      rd = if instr_name  {load_store_type SWAPA} then ― ‹rd› is member 4›
            get_operand_w5 (op_list!4)
           else ― ‹rd› is member 3›
            get_operand_w5 (op_list!3)
  in
  do
    psr_val  gets (λs. (cpu_reg_val PSR s));
    s_val  gets (λs. (get_S psr_val));
    if instr_name  {load_store_type SWAPA}  s_val = 0 then 
      do
        raise_trap privileged_instruction;
        return ()
      od
    else if instr_name  {load_store_type SWAPA}  flagi = 1 then
      do
        raise_trap illegal_instruction;
        return ()
      od
    else
      swap_sub1 instr rd s_val
  od"

definition bit2_zero :: "word2  word1"
where "bit2_zero w2  if w2  0 then 1 else 0"

text ‹Operational semantics for tagged add instructions.›
definition tadd_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "tadd_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    operand2  gets (λs. (get_operand2 op_list s));
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    psr_val  gets (λs. (cpu_reg_val PSR s));
    c_val  gets (λs. (get_icc_C psr_val));
    result  gets (λs. (rs1_val + operand2));
    result_31  gets (λs. ((ucast (result >> 31))::word1));
    rs1_val_31  gets (λs. ((ucast (rs1_val >> 31))::word1));
    operand2_31  gets (λs. ((ucast (operand2 >> 31))::word1));
    rs1_val_2  gets (λs. (bit2_zero ((ucast rs1_val)::word2)));
    operand2_2  gets (λs. (bit2_zero ((ucast operand2)::word2)));
    temp_V  gets (λs. ((OR) ((OR) ((AND) rs1_val_31 
                                              ((AND) operand2_31 
                                                      (NOT result_31))) 
                                      ((AND) (NOT rs1_val_31) 
                                              ((AND) (NOT operand2_31) 
                                                      result_31)))
                               ((OR) rs1_val_2 operand2_2)));
    if instr_name = arith_type TADDccTV  temp_V = 1 then 
    do
      raise_trap tag_overflow;
      return ()
    od
    else 
    do
      rd_val  gets (λs. (user_reg_val curr_win rd s));
      new_rd_val  gets (λs. (if rd  0 then result else rd_val));
      write_reg new_rd_val curr_win rd;      
      new_n_val  gets (λs. (result_31));
      new_z_val  gets (λs. (if result = 0 then 1::word1 else 0::word1));
      new_v_val  gets (λs. temp_V);
      new_c_val  gets (λs. ((OR) ((AND) rs1_val_31 
                                              operand2_31) 
                                      ((AND) (NOT result_31) 
                                              ((OR) rs1_val_31 
                                                     operand2_31))));
      new_psr_val  gets (λs. (update_PSR_icc new_n_val 
                                                 new_z_val 
                                                 new_v_val 
                                                 new_c_val psr_val));
      write_cpu new_psr_val PSR;
      rd_val  gets (λs. (user_reg_val curr_win rd s));
      new_rd_val  gets (λs. (if rd  0 then result else rd_val));
      write_reg new_rd_val curr_win rd;
      return ()
    od
  od"

text ‹Operational semantics for tagged add instructions.›
definition tsub_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "tsub_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    operand2  gets (λs. (get_operand2 op_list s));
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    psr_val  gets (λs. (cpu_reg_val PSR s));
    c_val  gets (λs. (get_icc_C psr_val));
    result  gets (λs. (rs1_val - operand2));
    result_31  gets (λs. ((ucast (result >> 31))::word1));
    rs1_val_31  gets (λs. ((ucast (rs1_val >> 31))::word1));
    operand2_31  gets (λs. ((ucast (operand2 >> 31))::word1));
    rs1_val_2  gets (λs. (bit2_zero ((ucast rs1_val)::word2)));
    operand2_2  gets (λs. (bit2_zero ((ucast operand2)::word2)));
    temp_V  gets (λs. ((OR) ((OR) ((AND) rs1_val_31 
                                              ((AND) operand2_31 
                                                      (NOT result_31))) 
                                      ((AND) (NOT rs1_val_31) 
                                              ((AND) (NOT operand2_31) 
                                                      result_31)))
                               ((OR) rs1_val_2 operand2_2)));
    if instr_name = arith_type TSUBccTV  temp_V = 1 then 
    do
      raise_trap tag_overflow;
      return ()
    od
    else 
    do
      rd_val  gets (λs. (user_reg_val curr_win rd s));
      new_rd_val  gets (λs. (if rd  0 then result else rd_val));
      write_reg new_rd_val curr_win rd;      
      new_n_val  gets (λs. (result_31));
      new_z_val  gets (λs. (if result = 0 then 1::word1 else 0::word1));
      new_v_val  gets (λs. temp_V);
      new_c_val  gets (λs. ((OR) ((AND) rs1_val_31 
                                              operand2_31) 
                                      ((AND) (NOT result_31) 
                                              ((OR) rs1_val_31 
                                                     operand2_31))));
      new_psr_val  gets (λs. (update_PSR_icc new_n_val 
                                                 new_z_val 
                                                 new_v_val 
                                                 new_c_val psr_val));
      write_cpu new_psr_val PSR;
      rd_val  gets (λs. (user_reg_val curr_win rd s));
      new_rd_val  gets (λs. (if rd  0 then result else rd_val));
      write_reg new_rd_val curr_win rd;
      return ()
    od
  od"

definition muls_op2 :: "inst_operand list  ('a::len) sparc_state  word32"
where "muls_op2 op_list s 
  let y_val = cpu_reg_val Y s in
  if ((ucast y_val)::word1) = 0 then 0
  else get_operand2 op_list s
"

text ‹Operational semantics for multiply step instruction.›
definition muls_instr :: "instruction  ('a::len,unit) sparc_state_monad"
where "muls_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1);
      rd = get_operand_w5 (op_list!3)
  in
  do
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    psr_val  gets (λs. (cpu_reg_val PSR s));
    n_val  gets (λs. (get_icc_N psr_val));
    v_val  gets (λs. (get_icc_V psr_val));
    c_val  gets (λs. (get_icc_C psr_val));
    y_val  gets (λs. (cpu_reg_val Y s));
    operand1  gets (λs. (word_cat ((XOR) n_val v_val) 
                                    ((ucast (rs1_val >> 1))::word31)));
    operand2  gets (λs. (muls_op2 op_list s));    
    result  gets (λs. (operand1 + operand2));
    new_y_val  gets (λs. (word_cat ((ucast rs1_val)::word1) ((ucast (y_val >> 1))::word31)));
    write_cpu new_y_val Y;
    rd_val  gets (λs. (user_reg_val curr_win rd s));
    new_rd_val  gets (λs. (if rd  0 then result else rd_val));
    write_reg new_rd_val curr_win rd;
    result_31  gets (λs. ((ucast (result >> 31))::word1));
    operand1_31  gets (λs. ((ucast (operand1 >> 31))::word1));
    operand2_31  gets (λs. ((ucast (operand2 >> 31))::word1));
    new_n_val  gets (λs. (result_31));
    new_z_val  gets (λs. (if result = 0 then 1::word1 else 0::word1));
    new_v_val  gets (λs. ((OR) ((AND) operand1_31 
                                  ((AND) operand2_31 
                                     (NOT result_31))) 
                                  ((AND) (NOT operand1_31) 
                                     ((AND) (NOT operand2_31) 
                                             result_31))));
    new_c_val  gets (λs. ((OR) ((AND) operand1_31 
                                          operand2_31) 
                                  ((AND) (NOT result_31) 
                                          ((OR) operand1_31 
                                                 operand2_31))));
    new_psr_val  gets (λs. (update_PSR_icc new_n_val 
                                             new_z_val 
                                             new_v_val 
                                             new_c_val psr_val));
    write_cpu new_psr_val PSR;
    return ()
  od"

text‹Evaluate icc based on the bits N, Z, V, C in PSR 
       and the type of ticc instruction. 
       See Sparcv8 manual Page 182.›
definition trap_eval_icc::"sparc_operation  word1  word1  word1  word1  int"
where "trap_eval_icc instr_name n_val z_val v_val c_val 
    if instr_name = ticc_type TNE then
      if z_val = 0 then 1 else 0
    else if instr_name = ticc_type TE then 
      if z_val = 1 then 1 else 0
    else if instr_name = ticc_type TG then
      if ((OR) z_val (n_val XOR v_val)) = 0 then 1 else 0
    else if instr_name = ticc_type TLE then
      if ((OR) z_val (n_val XOR v_val)) = 1 then 1 else 0
    else if instr_name = ticc_type TGE then
      if (n_val XOR v_val) = 0 then 1 else 0
    else if instr_name = ticc_type TL then
      if (n_val XOR v_val) = 1 then 1 else 0
    else if instr_name = ticc_type TGU then
      if (c_val = 0  z_val = 0) then 1 else 0
    else if instr_name = ticc_type TLEU then
      if (c_val = 1  z_val = 1) then 1 else 0
    else if instr_name = ticc_type TCC then
      if c_val = 0 then 1 else 0
    else if instr_name = ticc_type TCS then
      if c_val = 1 then 1 else 0
    else if instr_name = ticc_type TPOS then
      if n_val = 0 then 1 else 0
    else if instr_name = ticc_type TNEG then
      if n_val = 1 then 1 else 0
    else if instr_name = ticc_type TVC then
      if v_val = 0 then 1 else 0
    else if instr_name = ticc_type TVS then
      if v_val = 1 then 1 else 0
    else if instr_name = ticc_type TA then 1
    else if instr_name = ticc_type TN then 0    
    else -1
"

text ‹
  Get operand2› for ticc› based on the flag i›, rs1›, rs2›, and trap_imm7›.
  If i = 0› then operand2 = r[rs2]›,
  else operand2 = sign_ext7(trap_imm7)›.
  op_list› should be [i,rs1,rs2]› or [i,rs1,trap_imm7]›.
›
definition get_trap_op2::"inst_operand list  ('a::len) sparc_state
   virtua_address"
where "get_trap_op2 op_list s 
  let flagi = get_operand_flag (op_list!0);
      curr_win = ucast (get_CWP (cpu_reg_val PSR s))
  in
  if flagi = 0 then
    let rs2 = get_operand_w5 (op_list!2);
        rs2_val = user_reg_val curr_win rs2 s
    in rs2_val
  else
    let ext_simm7 = sign_ext7 (get_operand_imm7 (op_list!2)) in
    ext_simm7
"

text ‹Operational semantics for Ticc insturctions.›
definition ticc_instr::"instruction  
  ('a::len,unit) sparc_state_monad"
where "ticc_instr instr 
  let instr_name = fst instr;
      op_list = snd instr;
      rs1 = get_operand_w5 (op_list!1)
  in
  do
    n_val  gets (λs. get_icc_N ((cpu_reg s) PSR));
    z_val  gets (λs. get_icc_Z ((cpu_reg s) PSR));
    v_val  gets (λs. get_icc_V ((cpu_reg s) PSR));
    c_val  gets (λs. get_icc_C ((cpu_reg s) PSR));
    icc_val  gets(λs. (trap_eval_icc instr_name n_val z_val v_val c_val));
    curr_win  get_curr_win();
    rs1_val  gets (λs. (user_reg_val curr_win rs1 s));
    trap_number  gets (λs. (rs1_val + (get_trap_op2 op_list s)));
    npc_val  gets (λs. (cpu_reg_val nPC s));
    pc_val  gets (λs. (cpu_reg_val PC s));  
    if icc_val = 1 then 
      do
        raise_trap trap_instruction;
        trap_number7  gets (λs. ((ucast trap_number)::word7));
        modify (λs. (ticc_trap_type_mod trap_number7 s)); 
        return ()
      od
    else ― ‹icc_val = 0›
      do
        write_cpu npc_val PC;
        write_cpu (npc_val + 4) nPC;
        return ()
      od
  od"

text ‹Operational semantics for store barrier.›
definition store_barrier_instr::"instruction  ('a::len,unit) sparc_state_monad"
where "store_barrier_instr instr 
  do
    modify (λs. (store_barrier_pending_mod True s));
    return ()
  od"

end

Theory Sparc_Execution

(*
 * Copyright 2016, NTU
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * Author: Zhe Hou, David Sanan.
 *)

theory Sparc_Execution
imports Main Sparc_Instruction Sparc_State Sparc_Types 
"HOL-Eisbach.Eisbach_Tools"
begin

primrec sum :: "nat  nat" where
"sum 0 = 0" |
"sum (Suc n) = Suc n + sum n"

definition select_trap :: "unit  ('a,unit) sparc_state_monad"
where "select_trap _ 
  do
    traps  gets (λs. (get_trap_set s));
    rt_val  gets (λs. (reset_trap_val s));
    psr_val  gets (λs. (cpu_reg_val PSR s));
    et_val  gets (λs. (get_ET psr_val));
    modify (λs. (emp_trap_set s));
    if rt_val = True then ― ‹ignore ET›, and leave tt› unchaged›
      return ()
    else if et_val = 0 then ― ‹go to error mode, machine needs reset›
      do
        set_err_mode True;
        set_exe_mode False;
        fail ()
      od
    ― ‹By the SPARCv8 manual only 1 of the following traps could be in traps.›
    else if data_store_error  traps  then
      do
        write_cpu_tt (0b00101011::word8);
        return ()
      od
    else if instruction_access_error  traps then
      do
        write_cpu_tt (0b00100001::word8);
        return ()
      od
    else if r_register_access_error  traps then
      do
        write_cpu_tt (0b00100000::word8);
        return ()
      od
    else if instruction_access_exception  traps then
      do
        write_cpu_tt (0b00000001::word8);
        return ()
      od
    else if privileged_instruction  traps then  
      do
        write_cpu_tt (0b00000011::word8);
        return ()
      od
    else if illegal_instruction  traps then
      do
        write_cpu_tt (0b00000010::word8);
        return ()
      od
    else if fp_disabled  traps then
      do
        write_cpu_tt (0b00000100::word8);
        return ()
      od
    else if cp_disabled  traps then
      do
        write_cpu_tt (0b00100100::word8);
        return ()
      od
    else if unimplemented_FLUSH  traps then
      do
        write_cpu_tt (0b00100101::word8);
        return ()
      od
    else if window_overflow  traps then
      do
        write_cpu_tt (0b00000101::word8);
        return ()
      od
    else if window_underflow  traps then
      do
        write_cpu_tt (0b00000110::word8);
        return ()
      od  
    else if mem_address_not_aligned  traps then
      do
        write_cpu_tt (0b00000111::word8);
        return ()
      od
    else if fp_exception  traps then
      do  
        write_cpu_tt (0b00001000::word8);
        return ()
      od
    else if cp_exception  traps then
      do
        write_cpu_tt (0b00101000::word8);
        return ()
      od
    else if data_access_error  traps then
      do
        write_cpu_tt (0b00101001::word8);
        return ()
      od
    else if data_access_exception  traps then
      do
        write_cpu_tt (0b00001001::word8);
        return ()
      od  
    else if tag_overflow  traps then
      do
        write_cpu_tt (0b00001010::word8);
        return ()
      od
    else if division_by_zero  traps then
      do
        write_cpu_tt (0b00101010::word8);
        return ()
      od
    else if trap_instruction  traps then
      do 
        ticc_trap_type  gets (λs. (ticc_trap_type_val s));
        write_cpu_tt (word_cat (1::word1) ticc_trap_type);
        return ()
      od
    ⌦‹else if interrupt_level > 0 then›
    ― ‹We don't consider interrupt_level›
    else return ()
  od"

definition exe_trap_st_pc :: "unit  ('a::len,unit) sparc_state_monad"
where "exe_trap_st_pc _ 
  do
    annul  gets (λs. (annul_val s));
    pc_val  gets (λs. (cpu_reg_val PC s));
    npc_val  gets (λs. (cpu_reg_val nPC s));
    curr_win  get_curr_win();
    if annul = False then
      do
        write_reg pc_val curr_win (word_of_int 17);
        write_reg npc_val curr_win (word_of_int 18);
        return ()
      od
    else ― ‹annul = True›
      do
        write_reg npc_val curr_win (word_of_int 17);
        write_reg (npc_val + 4) curr_win (word_of_int 18);
        set_annul False;
        return ()
      od
  od"

definition exe_trap_wr_pc :: "unit  ('a::len,unit) sparc_state_monad"
where "exe_trap_wr_pc _ 
  do
    psr_val  gets (λs. (cpu_reg_val PSR s));
    new_psr_val  gets (λs. (update_S (1::word1) psr_val));
    write_cpu new_psr_val PSR;
    reset_trap  gets (λs. (reset_trap_val s));
    tbr_val  gets (λs. (cpu_reg_val TBR s));
    if reset_trap = False then
      do
        write_cpu tbr_val PC;
        write_cpu (tbr_val + 4) nPC;
        return ()
      od
    else ― ‹reset_trap = True›
      do
        write_cpu 0 PC;
        write_cpu 4 nPC;
        set_reset_trap False;
        return ()
      od
  od"
  
definition execute_trap :: "unit  ('a::len,unit) sparc_state_monad"
where "execute_trap _ 
  do
    select_trap();
    err_mode  gets (λs. (err_mode_val s));
    if err_mode = True then 
      ― ‹The SparcV8 manual doesn't say what to do.›
      return ()
    else
      do
        psr_val  gets (λs. (cpu_reg_val PSR s));
        s_val  gets (λs. ((ucast (get_S psr_val))::word1));
        curr_win  get_curr_win();
        new_cwp  gets (λs. ((word_of_int (((uint curr_win) - 1) mod NWINDOWS)))::word5);
        new_psr_val  gets (λs. (update_PSR_exe_trap new_cwp (0::word1) s_val psr_val));
        write_cpu new_psr_val PSR;          
        exe_trap_st_pc();         
        exe_trap_wr_pc();
        return ()
      od  
  od"

definition dispatch_instruction :: "instruction  ('a::len,unit) sparc_state_monad"
where "dispatch_instruction instr  
  let instr_name = fst instr in
  do
    traps  gets (λs. (get_trap_set s));
    if traps = {} then 
      if instr_name  {load_store_type LDSB,load_store_type LDUB,
        load_store_type LDUBA,load_store_type LDUH,load_store_type LD,
        load_store_type LDA,load_store_type LDD} then
        load_instr instr
      else if instr_name  {load_store_type STB,load_store_type STH,
        load_store_type ST,load_store_type STA,load_store_type STD} then
        store_instr instr
      else if instr_name  {sethi_type SETHI} then
        sethi_instr instr
      else if instr_name  {nop_type NOP} then
        nop_instr instr
      else if instr_name  {logic_type ANDs,logic_type ANDcc,logic_type ANDN,
        logic_type ANDNcc,logic_type ORs,logic_type ORcc,logic_type ORN,
        logic_type XORs,logic_type XNOR} then
        logical_instr instr
      else if instr_name  {shift_type SLL,shift_type SRL,shift_type SRA} then
        shift_instr instr
      else if instr_name  {arith_type ADD,arith_type ADDcc,arith_type ADDX} then
        add_instr instr
      else if instr_name  {arith_type SUB,arith_type SUBcc,arith_type SUBX} then
        sub_instr instr
      else if instr_name  {arith_type UMUL,arith_type SMUL,arith_type SMULcc} then
        mul_instr instr
      else if instr_name  {arith_type UDIV,arith_type UDIVcc,arith_type SDIV} then
        div_instr instr
      else if instr_name  {ctrl_type SAVE,ctrl_type RESTORE} then
        save_restore_instr instr
      else if instr_name  {call_type CALL} then
        call_instr instr
      else if instr_name  {ctrl_type JMPL} then
        jmpl_instr instr
      else if instr_name  {ctrl_type RETT} then
        rett_instr instr
      else if instr_name  {sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,
        sreg_type RDTBR} then
        read_state_reg_instr instr
      else if instr_name  {sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,
        sreg_type WRTBR} then 
        write_state_reg_instr instr
      else if instr_name  {load_store_type FLUSH} then
        flush_instr instr
      else if instr_name  {bicc_type BE,bicc_type BNE,bicc_type BGU,
        bicc_type BLE,bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
        bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,bicc_type BN} then
        branch_instr instr
      else fail ()
    else return ()
  od"

definition supported_instruction :: "sparc_operation  bool"
where "supported_instruction instr 
  if instr  {load_store_type LDSB,load_store_type LDUB,load_store_type LDUBA,
              load_store_type LDUH,load_store_type LD,load_store_type LDA,
              load_store_type LDD,
              load_store_type STB,load_store_type STH,load_store_type ST,
              load_store_type STA,load_store_type STD,
              sethi_type SETHI,
              nop_type NOP,
              logic_type ANDs,logic_type ANDcc,logic_type ANDN,logic_type ANDNcc,
              logic_type ORs,logic_type ORcc,logic_type ORN,logic_type XORs,
              logic_type XNOR,
              shift_type SLL,shift_type SRL,shift_type SRA,
              arith_type ADD,arith_type ADDcc,arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              ctrl_type RETT,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN} 
    then True
  else False
"

definition execute_instr_sub1 :: "instruction  ('a::len,unit) sparc_state_monad"
where "execute_instr_sub1 instr 
  do
    instr_name  gets (λs. (fst instr));
    traps2  gets (λs. (get_trap_set s));
    if traps2 = {}  instr_name  {call_type CALL,ctrl_type RETT,ctrl_type JMPL,
                                   bicc_type BE,bicc_type BNE,bicc_type BGU,
                                   bicc_type BLE,bicc_type BL,bicc_type BGE,
                                   bicc_type BNEG,bicc_type BG,
                                   bicc_type BCS,bicc_type BLEU,bicc_type BCC,
                                   bicc_type BA,bicc_type BN} then
    do
      npc_val  gets (λs. (cpu_reg_val nPC s));
      write_cpu npc_val PC;
      write_cpu (npc_val + 4) nPC;
      return ()
    od
    else return ()
  od"

definition execute_instruction :: "unit  ('a::len,unit) sparc_state_monad"
where "execute_instruction _  
  do
    traps  gets (λs. (get_trap_set s));
    if traps = {} then 
    do
      exe_mode  gets (λs. (exe_mode_val s));
      if exe_mode = True then
      do
        modify (λs. (delayed_pool_write s));
        fetch_result  gets (λs. (fetch_instruction s));
        case fetch_result of 
        Inl e1  (do ― ‹Memory address in PC is not aligned.›
                      ― ‹Actually, SparcV8 manual doens't check alignment here.›
                    raise_trap instruction_access_exception;
                    return ()
                  od) 
        | Inr v1  (do
          dec  gets (λs. (decode_instruction v1));
          case dec of 
            Inl e2  (― ‹Instruction is ill-formatted.›
                        fail ()
                      )
            | Inr v2  (do
              instr  gets (λs. (v2));
              annul  gets (λs. (annul_val s));
              if annul = False then 
              do
                dispatch_instruction instr;
                execute_instr_sub1 instr;
                return ()
              od
              else ― ‹annul ≠ False›
              do
                set_annul False;
                npc_val  gets (λs. (cpu_reg_val nPC s));
                write_cpu npc_val PC;
                write_cpu (npc_val + 4) nPC;
                return ()
              od
            od)
        od) 
      od
      else return () ― ‹Not in execute_mode›.›
    od
    else ― ‹traps is not empty, which means trap = 1›.›
    do
      execute_trap();
      return ()
    od
  od"

definition NEXT :: "('a::len)sparc_state  ('a)sparc_state option"
where "NEXT s  case execute_instruction () s of (_,True)  None
| (s',False)  Some (snd s')"

definition good_context :: "('a::len) sparc_state  bool"
where "good_context s  
  let traps = get_trap_set s;
      psr_val = cpu_reg_val PSR s;
      et_val = get_ET psr_val;
      rt_val = reset_trap_val s
  in
  if traps  {}  rt_val = False  et_val = 0 then False ― ‹enter error_mode› in select_traps›.›
  else
    let s' = delayed_pool_write s in
    case fetch_instruction s' of
    ― ‹instruction_access_exception› is handled in the next state.›
    Inl _  True 
    |Inr v  (
      case decode_instruction v of 
      Inl _  False 
      |Inr instr  (
        let annul = annul_val s' in
        if annul = True then True
        else ― ‹annul = False›
          if supported_instruction (fst instr) then
            ― ‹The only instruction that could fail is RETT›.›
            if (fst instr) = ctrl_type RETT then
              let curr_win_r = (get_CWP (cpu_reg_val PSR s'));
                  new_cwp_int_r = (((uint curr_win_r) + 1) mod NWINDOWS);
                  wim_val_r = cpu_reg_val WIM s';
                  psr_val_r = cpu_reg_val PSR s';
                  et_val_r = get_ET psr_val_r;
                  s_val_r = (ucast (get_S psr_val_r))::word1;
                  op_list_r = snd instr;
                  addr_r = get_addr (snd instr) s'
              in
              if et_val_r = 1 then True
              else if s_val_r = 0 then False
              else if (get_WIM_bit (nat new_cwp_int_r) wim_val_r)  0 then False
              else if ((AND) addr_r (0b00000000000000000000000000000011::word32))  0 then False
              else True
            else True
          else False ― ‹Unsupported instruction.›
      )  
    )
"

function (sequential) seq_exec:: "nat  ('a::len,unit) sparc_state_monad"
where "seq_exec 0 = return ()"
 |
"seq_exec n =  (do execute_instruction();
                  (seq_exec (n-1))
               od)
"
by pat_completeness auto
termination by lexicographic_order

type_synonym leon3_state = "(word_length5) sparc_state"

type_synonym ('e) leon3_state_monad = "(leon3_state, 'e) det_monad"

definition execute_leon3_instruction:: "unit  (unit) leon3_state_monad"
where "execute_leon3_instruction  execute_instruction"

definition seq_exec_leon3:: "nat  (unit) leon3_state_monad"
where "seq_exec_leon3  seq_exec"

end

Theory Sparc_Properties

(*
 * Copyright 2016, NTU
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * Author: Zhe Hou.
 *)

theory Sparc_Properties

imports Main Sparc_Execution

begin

(*********************************************************************)

section‹Single step theorem›

(*********************************************************************)

text ‹The following shows that, if the pre-state satisfies certain 
  conditions called good_context›, there must be a defined post-state 
  after a single step execution.›

method save_restore_proof =
((simp add: save_restore_instr_def),
 (simp add: Let_def simpler_gets_def bind_def h1_def h2_def),
 (simp add: case_prod_unfold),
 (simp add: raise_trap_def simpler_modify_def),
 (simp add: simpler_gets_def bind_def h1_def h2_def),
 (simp add: save_retore_sub1_def),
 (simp add: write_cpu_def simpler_modify_def),
 (simp add: write_reg_def simpler_modify_def),
 (simp add: get_curr_win_def),
 (simp add: simpler_gets_def bind_def h1_def h2_def))

method select_trap_proof0 = 
((simp add: select_trap_def exec_gets return_def),
 (simp add: DetMonad.bind_def h1_def h2_def simpler_modify_def),
 (simp add: write_cpu_tt_def write_cpu_def),
 (simp add: DetMonad.bind_def h1_def h2_def simpler_modify_def),
 (simp add: return_def simpler_gets_def))

method select_trap_proof1 =
((simp add: select_trap_def exec_gets return_def),
 (simp add: DetMonad.bind_def h1_def h2_def simpler_modify_def),
 (simp add: write_cpu_tt_def write_cpu_def),
 (simp add: DetMonad.bind_def h1_def h2_def simpler_modify_def),
 (simp add: return_def simpler_gets_def),
 (simp add: emp_trap_set_def err_mode_val_def cpu_reg_mod_def))

method dispatch_instr_proof1 =
((simp add: dispatch_instruction_def),
 (simp add: simpler_gets_def bind_def h1_def h2_def),
 (simp add: Let_def))

method exe_proof_to_decode =
((simp add: execute_instruction_def),
 (simp add: exec_gets bind_def h1_def h2_def Let_def return_def),
 clarsimp,
 (simp add: simpler_gets_def bind_def h1_def h2_def Let_def simpler_modify_def),
 (simp add: return_def))

method exe_proof_dispatch_rett =
((simp add: dispatch_instruction_def),
 (simp add: simpler_gets_def bind_def h1_def h2_def Let_def),
 (simp add: rett_instr_def),
 (simp add: simpler_gets_def bind_def h1_def h2_def Let_def))

lemma write_cpu_result: "snd (write_cpu w r s) = False"
by (simp add: write_cpu_def simpler_modify_def)

lemma set_annul_result: "snd (set_annul b s) = False"
by (simp add: set_annul_def simpler_modify_def)

lemma raise_trap_result : "snd (raise_trap t s) = False"
by (simp add: raise_trap_def simpler_modify_def)

lemma rett_instr_result: "(fst i) = ctrl_type RETT  
  (get_ET (cpu_reg_val PSR s)  1 
  (((get_S (cpu_reg_val PSR s)))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s)) = 0 
  ((AND) (get_addr (snd i) s) (0b00000000000000000000000000000011::word32)) = 0) 
  snd (rett_instr i s) = False"
apply (simp add: rett_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: write_cpu_def simpler_modify_def)
  apply (auto simp add: Let_def return_def)
  done

lemma call_instr_result: "(fst i) = call_type CALL 
  snd (call_instr i s) = False"
apply (simp add: call_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def case_prod_unfold)
apply (simp add: write_cpu_def write_reg_def)
apply (simp add: get_curr_win_def get_CWP_def)
by (simp add: simpler_modify_def simpler_gets_def)

lemma branch_instr_result: "(fst i)  {bicc_type BE,bicc_type BNE,bicc_type BGU,
 bicc_type BLE,bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
 bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,bicc_type BN}  
  snd (branch_instr i s) = False" 
proof (cases "eval_icc (fst i) (get_icc_N ((cpu_reg s) PSR)) (get_icc_Z ((cpu_reg s) PSR))
                           (get_icc_V ((cpu_reg s) PSR)) (get_icc_C ((cpu_reg s) PSR)) = 1")
  case True
  then have f1: "eval_icc (fst i) (get_icc_N ((cpu_reg s) PSR)) (get_icc_Z ((cpu_reg s) PSR))
                           (get_icc_V ((cpu_reg s) PSR)) (get_icc_C ((cpu_reg s) PSR)) = 1" 
    by auto
  then show ?thesis
  proof (cases "(fst i) = bicc_type BA  get_operand_flag ((snd i)!0) = 1")
    case True
    then show ?thesis using f1
    apply (simp add: branch_instr_def)
    apply (simp add: Let_def simpler_gets_def bind_def h1_def h2_def)    
    apply (simp add: set_annul_def case_prod_unfold)
    apply (simp add: write_cpu_def simpler_modify_def)
    by (simp add: return_def)   
  next
    case False
    then have f2: "¬ (fst i = bicc_type BA  get_operand_flag (snd i ! 0) = 1)" by auto
    then show ?thesis using f1
    apply (simp add: branch_instr_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: write_cpu_def simpler_modify_def)
    apply (simp add: branch_instr_sub1_def)
    apply (simp add: Let_def)
    apply auto
    apply (simp add: write_cpu_def simpler_modify_def)    
    by (simp add: write_cpu_def simpler_modify_def)
  qed
next
  case False
  then show ?thesis
  apply (simp add: branch_instr_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: write_cpu_def simpler_modify_def)
  apply (simp add: branch_instr_sub1_def)
  apply (simp add: Let_def)
  apply auto
   apply (simp add: Let_def bind_def h1_def h2_def)
   apply (simp add: write_cpu_def simpler_modify_def)
   apply (simp add: cpu_reg_mod_def set_annul_def simpler_modify_def)
  by (simp add: write_cpu_def simpler_modify_def)
qed

lemma nop_instr_result: "(fst i) = nop_type NOP 
  snd (nop_instr i s) = False"
apply (simp add: nop_instr_def)
by (simp add: returnOk_def return_def)

lemma sethi_instr_result: "(fst i) = sethi_type SETHI 
  snd (sethi_instr i s) = False"
apply (simp add: sethi_instr_def)
apply (simp add: Let_def)
apply (simp add: get_curr_win_def get_CWP_def cpu_reg_val_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: write_reg_def simpler_modify_def)
by (simp add: return_def)

lemma jmpl_instr_result: "(fst i) = ctrl_type JMPL 
  snd (jmpl_instr i s) = False"
apply (simp add: jmpl_instr_def)
apply (simp add: get_curr_win_def get_CWP_def cpu_reg_val_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: write_reg_def simpler_modify_def)
apply (simp add: write_cpu_def simpler_modify_def)
by (simp add: raise_trap_def simpler_modify_def)

lemma save_restore_instr_result: "(fst i)  {ctrl_type SAVE,ctrl_type RESTORE} 
  snd (save_restore_instr i s) = False"
proof (cases "(fst i) = ctrl_type SAVE")
  case True
  then show ?thesis
  by save_restore_proof
next
  case False
  then show ?thesis
  by save_restore_proof
qed

lemma flush_instr_result: "(fst i) = load_store_type FLUSH  
  snd (flush_instr i s) = False" 
apply (simp add: flush_instr_def)
by (simp add: simpler_gets_def bind_def h1_def h2_def simpler_modify_def)

lemma read_state_reg_instr_result: "(fst i)  {sreg_type RDY,sreg_type RDPSR,
  sreg_type RDWIM,sreg_type RDTBR} 
  snd (read_state_reg_instr i s) = False"
apply (simp add: read_state_reg_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: simpler_gets_def bind_def)
apply (simp add: write_reg_def simpler_modify_def)
apply (simp add: raise_trap_def simpler_modify_def return_def)
apply (simp add: bind_def h1_def h2_def)
by (simp add: get_curr_win_def simpler_gets_def)

lemma write_state_reg_instr_result: "(fst i)  {sreg_type WRY,sreg_type WRPSR,
  sreg_type WRWIM,sreg_type WRTBR} 
  snd (write_state_reg_instr i s) = False" 
apply (simp add: write_state_reg_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: simpler_modify_def)
apply (simp add: raise_trap_def simpler_modify_def return_def)
apply (simp add: bind_def h1_def h2_def)
apply (simp add: simpler_gets_def)
apply (simp add: write_cpu_def simpler_modify_def)
by (simp add: get_curr_win_def simpler_gets_def)

lemma logical_instr_result: "(fst i)  {logic_type ANDs,logic_type ANDcc,
  logic_type ANDN,logic_type ANDNcc,logic_type ORs,logic_type ORcc,
  logic_type ORN,logic_type XORs,logic_type XNOR} 
  snd (logical_instr i s) = False"
apply (simp add: logical_instr_def)
apply (simp add: Let_def simpler_gets_def)
apply (simp add: write_reg_def simpler_modify_def)
apply (simp add: bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: logical_instr_sub1_def)
apply (simp add: return_def)
apply (simp add: write_cpu_def simpler_modify_def)
apply (simp add: bind_def h1_def h2_def)
apply (simp add: case_prod_unfold)
apply (simp add: simpler_gets_def)
by (simp add: get_curr_win_def simpler_gets_def)

lemma shift_instr_result: "(fst i)  {shift_type SLL,shift_type 
  SRL,shift_type SRA} 
  snd (shift_instr i s) = False"
apply (simp add: shift_instr_def)
apply (simp add: Let_def)
apply (simp add: get_curr_win_def simpler_gets_def bind_def h1_def h2_def)
apply (simp add: return_def)
apply (simp add: bind_def h1_def h2_def)
by (simp add: write_reg_def simpler_modify_def)

method add_sub_instr_proof =
((simp add: Let_def),
 auto,
 (simp add: write_reg_def simpler_modify_def),
 (simp add: simpler_gets_def bind_def),
 (simp add: get_curr_win_def simpler_gets_def),
 (simp add: write_reg_def write_cpu_def simpler_modify_def),
 (simp add: bind_def),
 (simp add: case_prod_unfold),
 (simp add: simpler_gets_def),
 (simp add: get_curr_win_def simpler_gets_def),
 (simp add: write_reg_def simpler_modify_def),
 (simp add: simpler_gets_def bind_def),
 (simp add: get_curr_win_def simpler_gets_def))

lemma add_instr_result: "(fst i)  {arith_type ADD,arith_type 
  ADDcc,arith_type ADDX} 
  snd (add_instr i s) = False"
apply (simp add: add_instr_def)
apply (simp add: Let_def)
apply auto
  apply (simp add: add_instr_sub1_def)
  apply (simp add: write_reg_def simpler_modify_def)
  apply (simp add: bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply (simp add: simpler_gets_def)
  apply (simp add: get_curr_win_def simpler_gets_def)
 apply (simp add: add_instr_sub1_def)
 apply (simp add: write_reg_def simpler_modify_def)
 apply (simp add: simpler_gets_def bind_def h1_def h2_def)
 apply (simp add: get_curr_win_def simpler_gets_def)
 apply (simp add: write_cpu_def simpler_modify_def)
apply (simp add: add_instr_sub1_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: get_curr_win_def simpler_gets_def)
by (simp add: write_reg_def simpler_modify_def)

lemma sub_instr_result: "(fst i)  {arith_type SUB,arith_type SUBcc,
  arith_type SUBX} 
  snd (sub_instr i s) = False"
apply (simp add: sub_instr_def)
apply (simp add: Let_def)
apply auto
  apply (simp add: sub_instr_sub1_def)
  apply (simp add: write_reg_def simpler_modify_def)
  apply (simp add: bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply (simp add: simpler_gets_def)
  apply (simp add: get_curr_win_def simpler_gets_def)
 apply (simp add: sub_instr_sub1_def)
 apply (simp add: write_reg_def simpler_modify_def)
 apply (simp add: simpler_gets_def bind_def h1_def h2_def)
 apply (simp add: get_curr_win_def simpler_gets_def)
 apply (simp add: write_cpu_def simpler_modify_def)
apply (simp add: sub_instr_sub1_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: get_curr_win_def simpler_gets_def)
by (simp add: write_reg_def simpler_modify_def)

lemma mul_instr_result: "(fst i)  {arith_type UMUL,arith_type SMUL,
  arith_type SMULcc} 
  snd (mul_instr i s) = False"
apply (simp add: mul_instr_def)
apply (simp add: Let_def)
apply auto
  apply (simp add: mul_instr_sub1_def)
  apply (simp add: write_reg_def simpler_modify_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: get_curr_win_def simpler_gets_def)
  apply (simp add: write_reg_def write_cpu_def simpler_modify_def)
 apply (simp add: mul_instr_sub1_def)
 apply (simp add: simpler_gets_def)
 apply (simp add: write_cpu_def write_reg_def simpler_modify_def)
 apply (simp add: bind_def h1_def h2_def Let_def)
 apply (simp add: get_curr_win_def simpler_gets_def)
apply (simp add: mul_instr_sub1_def)
apply (simp add: simpler_gets_def)
apply (simp add: write_cpu_def write_reg_def simpler_modify_def)
apply (simp add: bind_def h1_def h2_def)
by (simp add: get_curr_win_def simpler_gets_def)

lemma div_write_new_val_result: "snd (div_write_new_val i result temp_V s) = False"
apply (simp add: div_write_new_val_def)
apply (simp add: return_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
by (simp add: write_cpu_def simpler_modify_def)

lemma div_result: "snd (div_comp instr rs1 rd operand2 s) = False"
apply (simp add: div_comp_def)
apply (simp add: simpler_gets_def)
apply (simp add: bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: write_reg_def simpler_modify_def)
apply (simp add: get_curr_win_def simpler_gets_def)
by (simp add: div_write_new_val_result)

lemma div_instr_result: "(fst i)  {arith_type UDIV,arith_type UDIVcc,
  arith_type SDIV} 
  snd (div_instr i s) = False"
apply (simp add: div_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: raise_trap_def simpler_modify_def)
apply (simp add: return_def bind_def)
by (simp add: div_result)

lemma load_sub2_result: "snd (load_sub2 address asi rd curr_win word0 s) = False"
apply (simp add: load_sub2_def)
apply (simp add: write_reg_def simpler_modify_def)
apply (simp add: bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: raise_trap_def simpler_modify_def)
apply (simp add: bind_def h1_def h2_def)
apply (simp add: write_reg_def simpler_modify_def)
by (simp add: simpler_gets_def)

lemma load_sub3_result: "snd (load_sub3 instr curr_win rd asi address s) = False"
apply (simp add: load_sub3_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: case_prod_unfold)
apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
apply (simp add: write_reg_def simpler_modify_def)
apply (simp add: load_sub2_result)
by (simp add: raise_trap_def simpler_modify_def)

lemma load_sub1_result: "snd (load_sub1 i rd s_val s) = False"
apply (simp add: load_sub1_def)
apply (simp add: bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: raise_trap_def simpler_modify_def)
apply (simp add: get_curr_win_def simpler_gets_def)
by (simp add: load_sub3_result)

lemma load_instr_result: "(fst i)  {load_store_type LDSB,load_store_type LDUB,
  load_store_type LDUBA,load_store_type LDUH,load_store_type LD,
  load_store_type LDA,load_store_type LDD} 
  snd (load_instr i s) = False"
apply (simp add: load_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: raise_trap_def simpler_modify_def)
apply (simp add: return_def)
by (simp add: load_sub1_result)

lemma store_sub2_result: "snd (store_sub2 instr curr_win rd asi address s) = False"
apply (simp add: store_sub2_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: raise_trap_def simpler_modify_def)
apply (simp add: return_def)
apply (simp add: raise_trap_def simpler_modify_def)
by (simp add: bind_def h1_def h2_def)

lemma store_sub1_result: "snd (store_sub1 instr rd s_val s) = False"
apply (simp add: store_sub1_def)
apply (simp add: bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: raise_trap_def simpler_modify_def)
apply (simp add: get_curr_win_def)
apply (simp add: simpler_gets_def)
by (simp add: store_sub2_result)

lemma store_instr_result: "(fst i)  {load_store_type STB,load_store_type STH,
  load_store_type ST,load_store_type STA,load_store_type STD} 
  snd (store_instr i s) = False"
apply (simp add: store_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: raise_trap_def simpler_modify_def)
apply (simp add: return_def)
by (simp add: store_sub1_result)

lemma supported_instr_set: "supported_instruction i = True  
  i  {load_store_type LDSB,load_store_type LDUB,load_store_type LDUBA,
              load_store_type LDUH,load_store_type LD,load_store_type LDA,
              load_store_type LDD,
              load_store_type STB,load_store_type STH,load_store_type ST,
              load_store_type STA,load_store_type STD,
              sethi_type SETHI,
              nop_type NOP,
              logic_type ANDs,logic_type ANDcc,logic_type ANDN,logic_type ANDNcc,
              logic_type ORs,logic_type ORcc,logic_type ORN,logic_type XORs,
              logic_type XNOR,
              shift_type SLL,shift_type SRL,shift_type SRA,
              arith_type ADD,arith_type ADDcc,arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              ctrl_type RETT,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
apply (simp add: supported_instruction_def)
by presburger

lemma dispatch_instr_result: 
assumes a1: "supported_instruction (fst i) = True  (fst i)  ctrl_type RETT"
shows "snd (dispatch_instruction i s) = False"
proof (cases "get_trap_set s = {}")
  case True
  then have f1: "get_trap_set s = {}" by auto
  then show ?thesis 
  proof (cases "(fst i)  {load_store_type LDSB,load_store_type LDUB,
    load_store_type LDUBA,load_store_type LDUH,load_store_type LD,
    load_store_type LDA,load_store_type LDD}")
    case True
    then show ?thesis using f1 
    apply dispatch_instr_proof1
    by (simp add: load_instr_result)
  next
    case False
    then have f2: "(fst i)  {load_store_type STB,load_store_type STH,load_store_type ST,
              load_store_type STA,load_store_type STD,
              sethi_type SETHI,
              nop_type NOP,
              logic_type ANDs,logic_type ANDcc,logic_type ANDN,logic_type ANDNcc,
              logic_type ORs,logic_type ORcc,logic_type ORN,logic_type XORs,
              logic_type XNOR,
              shift_type SLL,shift_type SRL,shift_type SRA,
              arith_type ADD,arith_type ADDcc,arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
     using a1 
     apply (simp add: supported_instruction_def)
     by presburger
     then show ?thesis 
     proof (cases "(fst i)  {load_store_type STB,load_store_type STH,
       load_store_type ST,
       load_store_type STA,load_store_type STD}")
      case True
      then show ?thesis using f1
      apply dispatch_instr_proof1      
      by (auto simp add: store_instr_result)
     next
      case False
      then have f3: "(fst i)  {sethi_type SETHI,
              nop_type NOP,
              logic_type ANDs,logic_type ANDcc,logic_type ANDN,logic_type ANDNcc,
              logic_type ORs,logic_type ORcc,logic_type ORN,logic_type XORs,
              logic_type XNOR,
              shift_type SLL,shift_type SRL,shift_type SRA,
              arith_type ADD,arith_type ADDcc,arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
      using f2 by auto
      then show ?thesis 
      proof (cases "(fst i) = sethi_type SETHI")
        case True
        then show ?thesis using f1
        apply dispatch_instr_proof1
        by (simp add: sethi_instr_result)
      next
        case False
        then have f4: "(fst i)  {nop_type NOP,
              logic_type ANDs,logic_type ANDcc,logic_type ANDN,logic_type ANDNcc,
              logic_type ORs,logic_type ORcc,logic_type ORN,logic_type XORs,
              logic_type XNOR,
              shift_type SLL,shift_type SRL,shift_type SRA,
              arith_type ADD,arith_type ADDcc,arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
        using f3 by auto         
        then show ?thesis 
        proof (cases "fst i = nop_type NOP")
          case True
          then show ?thesis using f1
          apply dispatch_instr_proof1
          by (simp add: nop_instr_result)
        next
          case False
          then have f5: "(fst i)  {logic_type ANDs,logic_type ANDcc,
              logic_type ANDN,logic_type ANDNcc,
              logic_type ORs,logic_type ORcc,logic_type ORN,logic_type XORs,
              logic_type XNOR,
              shift_type SLL,shift_type SRL,shift_type SRA,
              arith_type ADD,arith_type ADDcc,arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
          using f4 by auto
          then show ?thesis 
          proof (cases "(fst i)  {logic_type ANDs,logic_type ANDcc,
              logic_type ANDN,logic_type ANDNcc,
              logic_type ORs,logic_type ORcc,logic_type ORN,logic_type XORs,
              logic_type XNOR}")
            case True
            then show ?thesis using f1
            apply dispatch_instr_proof1
            by (auto simp add: logical_instr_result)
          next
            case False
            then have f6: "(fst i)  {shift_type SLL,shift_type SRL,
              shift_type SRA,
              arith_type ADD,arith_type ADDcc,arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
            using f5 by auto
            then show ?thesis 
            proof (cases "(fst i)  {shift_type SLL,shift_type SRL,
              shift_type SRA}")
              case True
              then show ?thesis using f1
              apply dispatch_instr_proof1
              by (auto simp add: shift_instr_result)
            next 
              case False
              then have f7: "(fst i)  {arith_type ADD,arith_type ADDcc,
              arith_type ADDX,
              arith_type SUB,arith_type SUBcc,arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}" 
              using f6 by auto
              then show ?thesis 
              proof (cases "(fst i)  {arith_type ADD,arith_type ADDcc,
              arith_type ADDX}")
                case True
                then show ?thesis using f1
                apply dispatch_instr_proof1
                by (auto simp add: add_instr_result)
              next
                case False
                then have f8: "(fst i)  {arith_type SUB,arith_type SUBcc,
                arith_type SUBX,
              arith_type UMUL,arith_type SMUL,arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                using f7 by auto
                then show ?thesis 
                proof (cases "(fst i)  {arith_type SUB,arith_type SUBcc,
                arith_type SUBX}")
                  case True
                  then show ?thesis using f1
                  apply dispatch_instr_proof1
                  by (auto simp add: sub_instr_result)
                next
                  case False
                  then have f9: "(fst i)  {arith_type UMUL,arith_type SMUL,
                  arith_type SMULcc,
              arith_type UDIV,arith_type UDIVcc,arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                  using f8 by auto
                  then show ?thesis 
                  proof (cases "(fst i)  {arith_type UMUL,arith_type SMUL,
                  arith_type SMULcc}")
                    case True
                    then show ?thesis using f1
                    apply dispatch_instr_proof1
                    by (auto simp add: mul_instr_result)
                  next
                    case False
                    then have f10: "(fst i)  {arith_type UDIV,arith_type UDIVcc,
                    arith_type SDIV,
              ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                    using f9 by auto
                    then show ?thesis 
                    proof (cases "(fst i)  {arith_type UDIV,arith_type UDIVcc,
                    arith_type SDIV}")
                      case True
                      then show ?thesis 
                      apply dispatch_instr_proof1 using f1
                      by (auto simp add: div_instr_result)
                    next
                      case False
                      then have f11: "(fst i)  {ctrl_type SAVE,ctrl_type RESTORE,
              call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                      using f10 by auto
                      then show ?thesis 
                      proof (cases "(fst i)  {ctrl_type SAVE,ctrl_type RESTORE}")
                        case True
                        then show ?thesis using f1
                        apply dispatch_instr_proof1 
                        by (auto simp add: save_restore_instr_result)
                      next
                        case False
                        then have f12: "(fst i)  {call_type CALL,
              ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                        using f11 by auto
                        then show ?thesis 
                        proof (cases "(fst i) = call_type CALL")
                          case True
                          then show ?thesis using f1
                          apply dispatch_instr_proof1
                          by (auto simp add: call_instr_result)
                        next
                          case False
                          then have f13: "(fst i)  {ctrl_type JMPL,
              sreg_type RDY,sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                          using f12 by auto
                          then show ?thesis 
                          proof (cases "(fst i) = ctrl_type JMPL")
                            case True
                            then show ?thesis using f1
                            apply dispatch_instr_proof1
                            by (auto simp add: jmpl_instr_result)
                          next
                            case False
                            then have f14: "(fst i)  {
                            sreg_type RDY,
                            sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR,
              sreg_type WRY,sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                            using f13 by auto
                            then show ?thesis 
                            proof (cases "(fst i)  {sreg_type RDY,
                            sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR}")
                              case True
                              then show ?thesis using f1
                              apply dispatch_instr_proof1
                              by (auto simp add: read_state_reg_instr_result)
                            next
                              case False
                              then have f15: "(fst i)  {
                              sreg_type WRY,
                              sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR,
              load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                              using f14 by auto
                              then show ?thesis 
                              proof (cases "(fst i)  {sreg_type WRY,
                              sreg_type WRPSR,sreg_type WRWIM,sreg_type WRTBR}")
                                case True
                                then show ?thesis using f1
                                apply dispatch_instr_proof1
                                by (auto simp add: write_state_reg_instr_result)
                              next
                                case False
                                then have f16: "(fst i)  {
                                load_store_type FLUSH,
              bicc_type BE,bicc_type BNE,bicc_type BGU,bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                                using f15 by auto
                                then show ?thesis 
                                proof (cases "(fst i) = load_store_type FLUSH")
                                  case True
                                  then show ?thesis using f1
                                  apply dispatch_instr_proof1
                                  by (auto simp add: flush_instr_result)
                                next
                                  case False
                                  then have f17: "(fst i) 
                                  {
                                  bicc_type BE,bicc_type BNE,bicc_type BGU,
                                  bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA,
              bicc_type BN}"
                                  using f16 by auto
                                  then show ?thesis using f1
                                  proof (cases "(fst i)  {bicc_type BE,
                                    bicc_type BNE,bicc_type BGU,
                                  bicc_type BLE,
              bicc_type BL,bicc_type BGE,bicc_type BNEG,bicc_type BG,
              bicc_type BCS,bicc_type BLEU,bicc_type BCC,bicc_type BA
              }")
                                    case True
                                    then show ?thesis using f1
                                    apply dispatch_instr_proof1
                                    apply auto
                                               by (auto simp add: branch_instr_result)
                                  next
                                    case False
                                    then have f18: "(fst i)  {bicc_type BN}" 
                                    using f17 by auto
                                    then show ?thesis using f1
                                    apply dispatch_instr_proof1
                                    apply auto
                                    by (auto simp add: branch_instr_result)
                                  qed
                                qed
                              qed
                            qed
                          qed
                        qed
                      qed
                    qed
                  qed
                qed
              qed
            qed
          qed
        qed
      qed
     qed
  qed
next
  case False
  then show ?thesis
  apply (simp add: dispatch_instruction_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: Let_def)
  by (simp add: returnOk_def return_def)
qed

lemma dispatch_instr_result_rett: 
assumes a1: "(fst i) = ctrl_type RETT  (get_ET (cpu_reg_val PSR s)  1 
  (((get_S (cpu_reg_val PSR s)))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s)) = 0 
  ((AND) (get_addr (snd i) s) (0b00000000000000000000000000000011::word32)) = 0)"
shows "snd (dispatch_instruction i s) = False"
proof (cases "get_trap_set s = {}")
  case True
  then show ?thesis using a1
  apply (simp add: dispatch_instruction_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (simp add: rett_instr_result)
next
  case False
  then show ?thesis using a1
  apply (simp add: dispatch_instruction_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (simp add: return_def)
qed

lemma execute_instr_sub1_result: "snd (execute_instr_sub1 i s) = False"
proof (cases "get_trap_set s = {}  (fst i)  {call_type CALL,ctrl_type RETT,
  ctrl_type JMPL}")
  case True
  then show ?thesis 
  apply (simp add: execute_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: write_cpu_def simpler_modify_def)
  apply auto
     by (auto simp add: return_def)
next
  case False
  then show ?thesis
  apply (simp add: execute_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: write_cpu_def simpler_modify_def)
  by (auto simp add: return_def)
qed

lemma next_match : "snd (execute_instruction () s) = False 
  NEXT s = Some (snd (fst (execute_instruction () s)))"
apply (simp add: NEXT_def)
by (simp add: case_prod_unfold)

lemma exec_ss1 : "s'. (execute_instruction () s = (s', False))  
  s''. (execute_instruction() s = (s'', False))"
proof -
  assume "s'. (execute_instruction () s = (s', False))"
  hence "(snd (execute_instruction() s)) = False" 
         by (auto simp add: execute_instruction_def case_prod_unfold)         
  hence "(execute_instruction() s) = 
        ((fst (execute_instruction() s)),False)"
         by (metis (full_types) prod.collapse) 
  hence "s''. (execute_instruction() s = (s'', False))" 
        by blast
  thus ?thesis by assumption
qed

lemma exec_ss2 : "snd (execute_instruction() s) = False 
  snd (execute_instruction () s) = False"
proof -
  assume "snd (execute_instruction() s) = False"
  hence "snd (execute_instruction () s) = False" 
    by (auto simp add:execute_instruction_def)
  thus ?thesis by assumption
qed

lemma good_context_1 : "good_context s  s' = s 
  (get_trap_set s')  {}  (reset_trap_val s') = False  get_ET (cpu_reg_val PSR s') = 0 
   False"
proof -
  assume asm: "good_context s  s' = s 
    (get_trap_set s')  {}  (reset_trap_val s') = False  get_ET (cpu_reg_val PSR s') = 0"
  then have  "(get_trap_set s')  {}  (reset_trap_val s') = False  
  get_ET (cpu_reg_val PSR s') = 0  False" 
    by (simp add: good_context_def get_ET_def cpu_reg_val_def) 
  then show ?thesis using asm by auto 
qed

lemma fetch_instr_result_1 : "¬ (e. fetch_instruction s' = Inl e) 
  (v. fetch_instruction s' = Inr v)"
by (meson sumE)

lemma fetch_instr_result_2 : "(v. fetch_instruction s' = Inr v) 
  ¬ (e. fetch_instruction s' = Inl e)"
by force

lemma fetch_instr_result_3 : "(e. fetch_instruction s' = Inl e) 
  ¬ (v. fetch_instruction s' = Inr v)"
by auto

lemma decode_instr_result_1 : 
"¬(v2. ((decode_instruction v1)::(Exception list + instruction)) = Inr v2) 
  (e. ((decode_instruction v1)::(Exception list + instruction)) = Inl e)"
by (meson sumE)

lemma decode_instr_result_2 : 
"(e. ((decode_instruction v1)::(Exception list + instruction)) = Inl e) 
  ¬(v2. ((decode_instruction v1)::(Exception list + instruction)) = Inr v2)"
by force

lemma decode_instr_result_3 : "x = decode_instruction v1  y = decode_instruction v2 
   v1 = v2  x = y"
by auto

lemma decode_instr_result_4 : 
"¬ (e. ((decode_instruction v1)::(Exception list + instruction)) = Inl e) 
  (v2. ((decode_instruction v1)::(Exception list + instruction)) = Inr v2)"
by (meson sumE)

lemma good_context_2 : 
"good_context (s::(('a::len) sparc_state))  
 fetch_instruction (delayed_pool_write s) = Inr v1   
 ¬(v2. (decode_instruction v1::(Exception list + instruction)) = Inr v2) 
  False"
proof -
  assume "good_context s  
    fetch_instruction (delayed_pool_write s) = Inr v1  
    ¬(v2. ((decode_instruction v1)::(Exception list + instruction)) = Inr v2)"
  hence fact1: "good_context s  
    fetch_instruction (delayed_pool_write s) = Inr v1  
    (e. ((decode_instruction v1)::(Exception list + instruction)) = Inl e)" 
    using decode_instr_result_1 by auto
  hence fact2: "¬(e. fetch_instruction (delayed_pool_write s) = Inl e)" 
    using fetch_instr_result_2 by auto
  then have "fetch_instruction (delayed_pool_write s) = Inr v1  
            (e. ((decode_instruction v1)::(Exception list + instruction)) = Inl e) 
             False"
    proof (cases "(get_trap_set s)  {}  (reset_trap_val s) = False  
      get_ET (cpu_reg_val PSR s) = 0") 
      case True 
      from this fact1 show ?thesis using good_context_1 by blast
    next
      case False
        then have fact3: "(get_trap_set s) = {}  (reset_trap_val s)  False 
         get_ET (cpu_reg_val PSR s)  0"
          by auto
        then show ?thesis 
          using fact1 decode_instr_result_3
          by (metis (no_types, lifting) good_context_def sum.case(1) sum.case(2))        
    qed
  thus ?thesis using fact1 by auto
qed

lemma good_context_3 : 
"good_context (s::(('a::len) sparc_state))  
 s'' = delayed_pool_write s 
 fetch_instruction s'' = Inr v1   
 (decode_instruction v1::(Exception list + instruction)) = Inr v2 
 annul_val s'' = False  supported_instruction (fst v2) = False
  False"
proof -
  assume asm: "good_context (s::(('a::len) sparc_state))  
  s'' = delayed_pool_write s 
  fetch_instruction s'' = Inr v1   
  (decode_instruction v1::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  supported_instruction (fst v2) = False"
  then have "annul_val s'' = False  supported_instruction (fst v2) = False
     False"
    proof (cases "(get_trap_set s)  {}  (reset_trap_val s) = False  
      get_ET (cpu_reg_val PSR s) = 0")
      case True
      from this asm show ?thesis using good_context_1 by blast
    next 
      case False
      then have fact3: "(get_trap_set s) = {}  (reset_trap_val s)  False  
      get_ET (cpu_reg_val PSR s)  0"
        by auto
      thus ?thesis using asm by (auto simp add: good_context_def)
    qed
  thus ?thesis using asm by auto
qed

lemma good_context_4 : 
"good_context (s::(('a::len) sparc_state))  
 s'' = delayed_pool_write s 
 fetch_instruction s'' = Inr v1  
 ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
 annul_val s'' = False  
 supported_instruction (fst v2) = True  ― ‹This line is redundant›
 (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
 (((get_S (cpu_reg_val PSR s'')))::word1) = 0
  False"
proof -
  assume asm: "good_context (s::(('a::len) sparc_state))  
  s'' = delayed_pool_write s 
  fetch_instruction s'' = Inr v1  
  ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  
  supported_instruction (fst v2) = True  ― ‹This line is redundant›
  (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1) = 0"
  then have "(fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1) = 0  False"
    proof (cases "(get_trap_set s)  {}  (reset_trap_val s) = False  
      get_ET (cpu_reg_val PSR s) = 0")
      case True
      from this asm show ?thesis using good_context_1 by blast
    next 
      case False
      then have fact3: "(get_trap_set s) = {}  (reset_trap_val s)  False  
      get_ET (cpu_reg_val PSR s)  0"
        by auto
      thus ?thesis using asm by (auto simp add: good_context_def)
    qed
  thus ?thesis using asm by auto
qed

lemma good_context_5 : 
"good_context (s::(('a::len) sparc_state))  
 s'' = delayed_pool_write s 
 fetch_instruction s'' = Inr v1  
 ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
 annul_val s'' = False  
 supported_instruction (fst v2) = True  ― ‹This line is redundant›
 (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
 (((get_S (cpu_reg_val PSR s'')))::word1)  0 
 (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
  (cpu_reg_val WIM s''))  0
  False"
proof -
  assume asm: "good_context (s::(('a::len) sparc_state))  
  s'' = delayed_pool_write s 
  fetch_instruction s'' = Inr v1  
  ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  
  supported_instruction (fst v2) = True  ― ‹This line is redundant›
  (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s''))  0"
  then have "(fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s''))  0
   False"
    proof (cases "(get_trap_set s)  {}  (reset_trap_val s) = False  
      get_ET (cpu_reg_val PSR s) = 0")
      case True
      from this asm show ?thesis using good_context_1 by blast
    next 
      case False
      then have fact3: "(get_trap_set s) = {}  (reset_trap_val s)  False 
      get_ET (cpu_reg_val PSR s)  0"
        by auto
      thus ?thesis using asm by (auto simp add: good_context_def)
    qed
  thus ?thesis using asm by auto
qed

lemma good_context_6 : 
"good_context (s::(('a::len) sparc_state))  
 s'' = delayed_pool_write s 
 fetch_instruction s'' = Inr v1  
 ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
 annul_val s'' = False  
 supported_instruction (fst v2) = True  ― ‹This line is redundant›
 (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
 (((get_S (cpu_reg_val PSR s'')))::word1)  0 
 (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
  (cpu_reg_val WIM s'')) = 0 
 ((AND) (get_addr (snd v2) s'') (0b00000000000000000000000000000011::word32))  0
  False"
proof -
  assume asm: "good_context (s::(('a::len) sparc_state))  
  s'' = delayed_pool_write s 
  fetch_instruction s'' = Inr v1  
  ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  
  supported_instruction (fst v2) = True  ― ‹This line is redundant›
  (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s'')) = 0 
  ((AND) (get_addr (snd v2) s'') (0b00000000000000000000000000000011::word32))  0"
  then have "(fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s'')) = 0 
  ((AND) (get_addr (snd v2) s'') (0b00000000000000000000000000000011::word32))  0
   False"
    proof (cases "(get_trap_set s)  {}  (reset_trap_val s) = False  
      get_ET (cpu_reg_val PSR s) = 0")
      case True
      from this asm show ?thesis using good_context_1 by blast
    next 
      case False
      then have fact3: "(get_trap_set s) = {}  (reset_trap_val s)  False 
      get_ET (cpu_reg_val PSR s)  0"
        by auto
      thus ?thesis using asm by (auto simp add: good_context_def)
    qed
  thus ?thesis using asm by auto
qed

lemma good_context_all : 
"good_context (s::(('a::len) sparc_state))  
 s'' = delayed_pool_write s 
 (get_trap_set s = {}  (reset_trap_val s)  False  get_ET (cpu_reg_val PSR s)  0) 
 ((e. fetch_instruction s'' = Inl e)  
  (v1 v2. fetch_instruction s'' = Inr v1  
   ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
   (annul_val s'' = True 
    (annul_val s'' = False  
     (v1' v2'. fetch_instruction s'' = Inr v1'  
      ((decode_instruction v1')::(Exception list + instruction)) = Inr v2' 
      supported_instruction (fst v2') = True) 
     ((fst v2)  ctrl_type RETT 
      ((fst v2) = ctrl_type RETT  
       (get_ET (cpu_reg_val PSR s'') = 1 
        (get_ET (cpu_reg_val PSR s'')  1 
        (((get_S (cpu_reg_val PSR s'')))::word1)  0 
        (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
          (cpu_reg_val WIM s'')) = 0 
        ((AND) (get_addr (snd v2) s'') (0b00000000000000000000000000000011::word32)) = 0))))))))"
proof -
 assume asm: "good_context s  s'' = delayed_pool_write s"
 from asm have "(get_trap_set s)  {}  (reset_trap_val s) = False  
 get_ET (cpu_reg_val PSR s) = 0  False"
  using good_context_1 by blast  
 hence fact1: "(get_trap_set s = {}  (reset_trap_val s)  False  
 get_ET (cpu_reg_val PSR s)  0)" by auto
 have fact2: "¬(e. fetch_instruction s'' = Inl e)  ¬ (v1. fetch_instruction s'' = Inr v1) 
   False" using fetch_instr_result_1 by blast
 from asm have fact3: "v1. fetch_instruction s'' = Inr v1 
  ¬(v2.((decode_instruction v1)::(Exception list + instruction)) = Inr v2)
   False"
  using good_context_2 by blast
 from asm have fact4: "v1 v2. fetch_instruction s'' = Inr v1  
  ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  supported_instruction (fst v2) = False
   False"
  using good_context_3 by blast
 from asm have fact5: "v1 v2. fetch_instruction s'' = Inr v1  
  ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  supported_instruction (fst v2) = True 
  (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1) = 0
   False"
  using good_context_4 by blast
 from asm have fact6: "v1 v2. fetch_instruction s'' = Inr v1  
  ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  supported_instruction (fst v2) = True 
  (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s''))  0
   False" 
  using good_context_5 by blast
 from asm have fact7: "v1 v2. fetch_instruction s'' = Inr v1  
  ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
  annul_val s'' = False  supported_instruction (fst v2) = True 
  (fst v2) = ctrl_type RETT  get_ET (cpu_reg_val PSR s'')  1 
  (((get_S (cpu_reg_val PSR s'')))::word1)  0 
  (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) mod NWINDOWS)) 
    (cpu_reg_val WIM s'')) = 0 
  ((AND) (get_addr (snd v2) s'') (0b00000000000000000000000000000011::word32))  0
   False"
    using good_context_6 by blast
 from asm show ?thesis 
  proof (cases "(e. fetch_instruction s'' = Inl e)")
    case True
    then show ?thesis using fact1 by auto
  next 
    case False
    then have fact8: "v1. fetch_instruction s'' = Inr v1  
    (v2.((decode_instruction v1)::(Exception list + instruction)) = Inr v2)"
      using fact2 fact3 by auto
    then show ?thesis 
      proof (cases "annul_val s'' = True")
        case True
        then show ?thesis using fact1 fact8 by auto
      next 
        case False
        then have fact9: "v1 v2. fetch_instruction s'' = Inr v1  
        ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
        annul_val s'' = False  supported_instruction (fst v2) = True"
          using fact4 fact8 by blast
        then show ?thesis 
          proof (cases "v1 v2. fetch_instruction s'' = Inr v1  
            ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
            (fst v2)  ctrl_type RETT")
            case True
            then show ?thesis using fact1 fact9 by auto  
          next
            case False
            then have fact10: "v1 v2. fetch_instruction s'' = Inr v1  
            ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
            annul_val s'' = False  supported_instruction (fst v2) = True  
              (fst v2) = ctrl_type RETT"
              using fact9 by auto
            then show ?thesis 
              proof (cases "get_ET (cpu_reg_val PSR s'') = 1")
                case True
                then show ?thesis using fact1 fact9 by auto
              next
                case False
                then have fact11: "get_ET (cpu_reg_val PSR s'')  1  
                (((get_S (cpu_reg_val PSR s'')))::word1)  0"
                  using fact10 fact5 by auto
                then have fact12: "(get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR s''))) + 1) 
                  mod NWINDOWS)) (cpu_reg_val WIM s'')) = 0" 
                  using fact10 fact6 by auto
                then have fact13: "v1 v2. fetch_instruction s'' = Inr v1  
                ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
                ((AND) (get_addr (snd v2) s'') (0b00000000000000000000000000000011::word32)) = 0"
                  using fact10 fact11 fact7 by blast
                thus ?thesis using fact1 fact10 fact11 fact12 by auto
              qed
          qed
      qed
  qed
qed

lemma select_trap_result1 : "(reset_trap_val s) = True 
  snd (select_trap() s) = False"   
apply (simp add: select_trap_def exec_gets return_def)
by (simp add: bind_def  h1_def h2_def simpler_modify_def)

lemma select_trap_result2 : 
assumes a1: "¬(reset_trap_val s = False  get_ET (cpu_reg_val PSR s) = 0)"
shows  "snd (select_trap() s) = False"
proof (cases "reset_trap_val s = True") 
  case True
  then show ?thesis using select_trap_result1 
  by blast
next
  case False
  then have f1: "reset_trap_val s = False  get_ET (cpu_reg_val PSR s)  0"
    using a1 by auto
    then show ?thesis
    proof (cases "data_store_error  get_trap_set s")
      case True
      then show ?thesis using f1
      by select_trap_proof0
    next
      case False
      then have f2: "data_store_error  get_trap_set s" by auto
      then show ?thesis 
      proof (cases "instruction_access_error  get_trap_set s")
        case True
        then show ?thesis using f1 f2
        by select_trap_proof0
      next
        case False
        then have f3: "instruction_access_error  get_trap_set s" by auto
        then show ?thesis 
        proof (cases "r_register_access_error  get_trap_set s")
          case True
          then show ?thesis using f1 f2 f3
          by select_trap_proof0
        next
          case False
          then have f4: "r_register_access_error  get_trap_set s" by auto
          then show ?thesis 
          proof (cases "instruction_access_exception  get_trap_set s")
            case True
            then show ?thesis using f1 f2 f3 f4
            by select_trap_proof0
          next
            case False
            then have f5: "instruction_access_exception  get_trap_set s" by auto
            then show ?thesis 
            proof (cases "privileged_instruction  get_trap_set s")
              case True
              then show ?thesis using f1 f2 f3 f4 f5
              by select_trap_proof0
            next  
              case False
              then have f6: "privileged_instruction  get_trap_set s" by auto
              then show ?thesis 
              proof (cases "illegal_instruction  get_trap_set s")
                case True
                then show ?thesis using f1 f2 f3 f4 f5 f6
                by select_trap_proof0
              next
                case False
                then have f7: "illegal_instruction  get_trap_set s" by auto
                then show ?thesis
                proof (cases "fp_disabled  get_trap_set s")
                  case True
                  then show ?thesis using f1 f2 f3 f4 f5 f6 f7
                  by select_trap_proof0
                next
                  case False
                  then have f8: "fp_disabled  get_trap_set s" by auto
                  then show ?thesis 
                  proof (cases "cp_disabled  get_trap_set s")
                    case True
                    then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8
                    by select_trap_proof0
                  next
                    case False
                    then have f9: "cp_disabled  get_trap_set s" by auto
                    then show ?thesis 
                    proof (cases "unimplemented_FLUSH  get_trap_set s")
                      case True
                      then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9
                      by select_trap_proof0
                    next
                      case False
                      then have f10: "unimplemented_FLUSH  get_trap_set s" by auto
                      then show ?thesis 
                      proof (cases "window_overflow  get_trap_set s")
                        case True
                        then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10
                        by select_trap_proof0
                      next 
                        case False
                        then have f11: "window_overflow  get_trap_set s" by auto
                        then show ?thesis 
                        proof (cases "window_underflow  get_trap_set s")
                          case True
                          then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11
                          by select_trap_proof0
                        next
                          case False
                          then have f12: "window_underflow  get_trap_set s" by auto
                          then show ?thesis 
                          proof (cases "mem_address_not_aligned  get_trap_set s")
                            case True
                            then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
                            by select_trap_proof0
                          next
                            case False
                            then have f13: "mem_address_not_aligned  get_trap_set s" by auto
                            then show ?thesis 
                            proof (cases "fp_exception  get_trap_set s")
                              case True
                              then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                              by select_trap_proof0
                            next
                              case False
                              then have f14: "fp_exception  get_trap_set s" by auto
                              then show ?thesis 
                              proof (cases "cp_exception  get_trap_set s")
                                case True
                                then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                                f14 
                                by select_trap_proof0
                              next
                                case False
                                then have f15: "cp_exception  get_trap_set s" by auto
                                then show ?thesis 
                                proof (cases "data_access_error  get_trap_set s")
                                  case True
                                  then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                                f14 f15 
                                by select_trap_proof0
                                next
                                  case False
                                  then have f16: "data_access_error  get_trap_set s" by auto
                                  then show ?thesis 
                                  proof (cases "data_access_exception  get_trap_set s")
                                    case True
                                    then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 
                                    f13 f14 f15 f16
                                    by select_trap_proof0
                                  next
                                    case False
                                    then have f17: "data_access_exception  get_trap_set s" by auto
                                    then show ?thesis 
                                    proof (cases "tag_overflow  get_trap_set s")
                                      case True
                                      then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 
                                      f13 f14 f15 f16 f17
                                      by select_trap_proof0
                                    next
                                      case False
                                      then have f18: "tag_overflow  get_trap_set s" by auto
                                      then show ?thesis 
                                      proof (cases "division_by_zero  get_trap_set s")
                                        case True
                                        then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 
                                        f12 f13 f14 f15 f16 f17 f18 
                                        by select_trap_proof0
                                      next
                                        case False
                                        then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 
                                        f12 f13 f14 f15 f16 f17 f18
                                        apply (simp add: select_trap_def exec_gets return_def)
                                        apply (simp add: DetMonad.bind_def h1_def h2_def simpler_modify_def)
                                        apply (simp add: return_def simpler_gets_def)
                                        apply (simp add: case_prod_unfold)
                                        apply (simp add: return_def)
                                        apply (simp add: write_cpu_tt_def write_cpu_def)
                                        by (simp add: simpler_gets_def bind_def h1_def h2_def simpler_modify_def)
                                      qed
                                    qed
                                  qed
                                qed
                              qed
                            qed
                          qed
                        qed
                      qed
                    qed
                  qed
                qed
              qed
            qed
          qed
        qed
      qed
    qed
qed

lemma emp_trap_set_err_mode : "err_mode_val s = err_mode_val (emp_trap_set s)"
by (auto simp add: emp_trap_set_def err_mode_val_def)

lemma write_cpu_tt_err_mode : "err_mode_val s = err_mode_val (snd (fst (write_cpu_tt w s)))"
apply (simp add: write_cpu_tt_def err_mode_val_def write_cpu_def)  
apply (simp add: exec_gets return_def)
apply (simp add: bind_def simpler_modify_def)
by (simp add: cpu_reg_mod_def)

lemma select_trap_monad : "snd (select_trap() s) = False  
  err_mode_val s = err_mode_val (snd (fst (select_trap () s)))"
proof -
  assume a1: "snd (select_trap() s) = False"
  then have f0: "reset_trap_val s = False  get_ET (cpu_reg_val PSR s) = 0  False" 
    apply (simp add: select_trap_def exec_gets return_def)
    apply (simp add: bind_def h1_def h2_def simpler_modify_def)
    by (simp add: fail_def split_def)  
  then show ?thesis
    proof (cases "reset_trap_val s = True")
      case True
      from a1 f0 this show ?thesis 
      apply (simp add: select_trap_def exec_gets return_def)
      apply (simp add: bind_def h1_def h2_def simpler_modify_def)
      by (simp add: emp_trap_set_def err_mode_val_def)
    next
      case False
      then have f1: "reset_trap_val s = False  get_ET (cpu_reg_val PSR s)  0" using f0 by auto
      then show ?thesis using f1 a1
      proof (cases "data_store_error  get_trap_set s")
        case True
        then show ?thesis using f1 a1
        by select_trap_proof1
      next 
        case False
        then have f2: "data_store_error  get_trap_set s" by auto
        then show ?thesis 
        proof (cases "instruction_access_error  get_trap_set s")
          case True
          then show ?thesis using f1 f2 a1
          by select_trap_proof1
        next
          case False
          then have f3: "instruction_access_error  get_trap_set s" by auto
          then show ?thesis 
          proof (cases "r_register_access_error  get_trap_set s")
            case True
            then show ?thesis using f1 f2 f3 a1
            by select_trap_proof1
          next
            case False
            then have f4: "r_register_access_error  get_trap_set s" by auto
            then show ?thesis 
            proof (cases "instruction_access_exception  get_trap_set s")
              case True
              then show ?thesis using f1 f2 f3 f4 a1
              by select_trap_proof1
            next
              case False
              then have f5: "instruction_access_exception  get_trap_set s" by auto
              then show ?thesis 
              proof (cases "privileged_instruction  get_trap_set s")
                case True
                then show ?thesis using f1 f2 f3 f4 f5 a1
                by select_trap_proof1
              next  
                case False
                then have f6: "privileged_instruction  get_trap_set s" by auto
                then show ?thesis 
                proof (cases "illegal_instruction  get_trap_set s")
                  case True
                  then show ?thesis using f1 f2 f3 f4 f5 f6 a1
                  by select_trap_proof1
                next
                  case False
                  then have f7: "illegal_instruction  get_trap_set s" by auto
                  then show ?thesis
                  proof (cases "fp_disabled  get_trap_set s")
                    case True
                    then show ?thesis using f1 f2 f3 f4 f5 f6 f7 a1
                    by select_trap_proof1
                  next
                    case False
                    then have f8: "fp_disabled  get_trap_set s" by auto
                    then show ?thesis 
                    proof (cases "cp_disabled  get_trap_set s")
                      case True
                      then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 a1
                      by select_trap_proof1
                    next
                      case False
                      then have f9: "cp_disabled  get_trap_set s" by auto
                      then show ?thesis 
                      proof (cases "unimplemented_FLUSH  get_trap_set s")
                        case True
                        then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 a1
                        by select_trap_proof1
                      next
                        case False
                        then have f10: "unimplemented_FLUSH  get_trap_set s" by auto
                        then show ?thesis 
                        proof (cases "window_overflow  get_trap_set s")
                          case True
                          then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 a1
                          by select_trap_proof1
                        next 
                          case False
                          then have f11: "window_overflow  get_trap_set s" by auto
                          then show ?thesis 
                          proof (cases "window_underflow  get_trap_set s")
                            case True
                            then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 a1
                            by select_trap_proof1
                          next
                            case False
                            then have f12: "window_underflow  get_trap_set s" by auto
                            then show ?thesis 
                            proof (cases "mem_address_not_aligned  get_trap_set s")
                              case True
                              then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 a1
                              by select_trap_proof1
                            next
                              case False
                              then have f13: "mem_address_not_aligned  get_trap_set s" by auto
                              then show ?thesis 
                              proof (cases "fp_exception  get_trap_set s")
                                case True
                                then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                                a1
                                by select_trap_proof1
                              next
                                case False
                                then have f14: "fp_exception  get_trap_set s" by auto
                                then show ?thesis 
                                proof (cases "cp_exception  get_trap_set s")
                                  case True
                                  then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                                  f14 a1
                                  by select_trap_proof1
                                next
                                  case False
                                  then have f15: "cp_exception  get_trap_set s" by auto
                                  then show ?thesis 
                                  proof (cases "data_access_error  get_trap_set s")
                                    case True
                                    then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                                    f14 f15 a1
                                    by select_trap_proof1
                                  next
                                    case False
                                    then have f16: "data_access_error  get_trap_set s" by auto
                                    then show ?thesis 
                                    proof (cases "data_access_exception  get_trap_set s")
                                      case True
                                      then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 
                                      f13 f14 f15 f16 a1
                                      by select_trap_proof1
                                    next
                                      case False
                                      then have f17: "data_access_exception  get_trap_set s" by auto
                                      then show ?thesis 
                                      proof (cases "tag_overflow  get_trap_set s")
                                        case True
                                        then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 
                                        f13 f14 f15 f16 f17 a1
                                        by select_trap_proof1
                                      next
                                        case False
                                        then have f18: "tag_overflow  get_trap_set s" by auto
                                        then show ?thesis 
                                        proof (cases "division_by_zero  get_trap_set s")
                                          case True
                                          then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 
                                          f12 f13 f14 f15 f16 f17 f18 a1
                                          by select_trap_proof1
                                        next
                                          case False
                                          then show ?thesis using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 
                                          f12 f13 f14 f15 f16 f17 f18 a1
                                          apply (simp add: select_trap_def exec_gets return_def)
                                          apply (simp add: bind_def h1_def h2_def simpler_modify_def)
                                          apply (simp add: return_def simpler_gets_def)
                                          apply (simp add: emp_trap_set_def err_mode_val_def
                                            cpu_reg_mod_def)
                                          apply (simp add: case_prod_unfold)
                                          apply (simp add: return_def)
                                          apply clarsimp                                          
                                          apply (simp add: write_cpu_tt_def write_cpu_def write_tt_def)
                                          apply (simp add: simpler_gets_def bind_def h1_def h2_def)
                                          apply (simp add: simpler_modify_def)
                                          by (simp add: cpu_reg_val_def cpu_reg_mod_def)
                                        qed
                                      qed
                                    qed
                                  qed
                                qed
                              qed
                            qed
                          qed
                        qed
                      qed
                    qed
                  qed
                qed
              qed
            qed
          qed
        qed
      qed
    qed
qed

lemma exe_trap_st_pc_result : "snd (exe_trap_st_pc() s) = False"
proof (cases "annul_val s = True")
  case True
  then show ?thesis 
  apply (simp add: exe_trap_st_pc_def get_curr_win_def)
  apply (simp add: exec_gets return_def)
  apply (simp add: DetMonad.bind_def h1_def h2_def)
  by (simp add: set_annul_def write_reg_def simpler_modify_def)
next
  case False
  then show ?thesis
  apply (simp add: exe_trap_st_pc_def get_curr_win_def)
  apply (simp add: exec_gets return_def)
  apply (simp add: DetMonad.bind_def h1_def h2_def)
  by (simp add: write_reg_def simpler_modify_def)
qed

lemma exe_trap_wr_pc_result : "snd (exe_trap_wr_pc() s) = False"
proof (cases "reset_trap_val s = True")
  case True
  then show ?thesis 
  apply (simp add: exe_trap_wr_pc_def get_curr_win_def)
  apply (simp add: exec_gets return_def)
  apply (simp add: DetMonad.bind_def h1_def h2_def)
  apply (simp add: write_cpu_def simpler_modify_def)
  apply (simp add: simpler_gets_def)
  apply (simp add: cpu_reg_val_def update_S_def cpu_reg_mod_def reset_trap_val_def)
  apply (simp add: write_cpu_def simpler_modify_def DetMonad.bind_def h1_def h2_def)
  apply (simp add: return_def)
  by (simp add: set_reset_trap_def simpler_modify_def DetMonad.bind_def h1_def h2_def return_def)
next
  case False
  then show ?thesis
  apply (simp add: exe_trap_wr_pc_def get_curr_win_def)
  apply (simp add: exec_gets return_def)
  apply (simp add: DetMonad.bind_def h1_def h2_def)
  apply (simp add: write_cpu_def simpler_modify_def)
  apply (simp add: simpler_gets_def)
  apply (simp add: cpu_reg_val_def update_S_def cpu_reg_mod_def reset_trap_val_def)
  apply (simp add: write_cpu_def simpler_modify_def DetMonad.bind_def h1_def h2_def)
  by (simp add: return_def)
qed

lemma execute_trap_result : "¬(reset_trap_val s = False  get_ET (cpu_reg_val PSR s) = 0) 
  snd (execute_trap() s) = False"
proof -
  assume "¬(reset_trap_val s = False  get_ET (cpu_reg_val PSR s) = 0)"
  then have fact1: "snd (select_trap() s) = False" using select_trap_result2 by blast
  then show ?thesis 
    proof (cases "err_mode_val s = True")
      case True
      then show ?thesis using fact1 
        apply (simp add: execute_trap_def exec_gets return_def)
        apply (simp add: DetMonad.bind_def h1_def h2_def Let_def)
        apply (simp add: case_prod_unfold)
        by (simp add: in_gets return_def select_trap_monad simpler_gets_def)
    next 
      case False
      then show ?thesis using fact1 select_trap_monad
      apply (simp add: execute_trap_def exec_gets return_def)
      apply (simp add: DetMonad.bind_def h1_def h2_def)
      apply (simp add: case_prod_unfold)
      apply (simp add: simpler_gets_def)
      apply (auto simp add: select_trap_monad)
      apply (simp add: DetMonad.bind_def h1_def h2_def get_curr_win_def)
      apply (simp add: get_CWP_def cpu_reg_val_def)
      apply (simp add: simpler_gets_def return_def write_cpu_def)
      apply (simp add: simpler_modify_def DetMonad.bind_def h1_def h2_def)
      apply (simp add: exe_trap_st_pc_result)
      by (simp add: case_prod_unfold exe_trap_wr_pc_result)
    qed
qed

lemma execute_trap_result2 : "¬(reset_trap_val s = False  get_ET (cpu_reg_val PSR s) = 0) 
  snd (execute_trap() s) = False"
using execute_trap_result
by blast

lemma exe_instr_all : 
"good_context (s::(('a::len) sparc_state))  
  snd (execute_instruction() s) = False"
proof -
  assume asm1: "good_context s"
  let ?s' = "delayed_pool_write s"
  from asm1 have f1 : "(get_trap_set s = {}  (reset_trap_val s)  False  
  get_ET (cpu_reg_val PSR s)  0) 
  ((e. fetch_instruction ?s' = Inl e)  
  (v1 v2. fetch_instruction ?s' = Inr v1  
   ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
   (annul_val ?s' = True 
    (annul_val ?s' = False  
     (v1' v2'. fetch_instruction ?s' = Inr v1'  
      ((decode_instruction v1')::(Exception list + instruction)) = Inr v2' 
      supported_instruction (fst v2') = True) 
     ((fst v2)  ctrl_type RETT 
      ((fst v2) = ctrl_type RETT  
       (get_ET (cpu_reg_val PSR ?s') = 1 
        (get_ET (cpu_reg_val PSR ?s')  1 
        (((get_S (cpu_reg_val PSR ?s')))::word1)  0 
        (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR ?s'))) + 1) mod NWINDOWS)) 
          (cpu_reg_val WIM ?s')) = 0 
        ((AND) (get_addr (snd v2) ?s') (0b00000000000000000000000000000011::word32)) = 0))))))))"
       using good_context_all by blast
   from f1 have f2: "get_trap_set s  {}  
   (reset_trap_val s)  False  get_ET (cpu_reg_val PSR s)  0" 
    by auto
   show ?thesis 
   proof (cases "get_trap_set s = {}")
    case True
    then have f3: "get_trap_set s = {}" by auto
    then show ?thesis
    proof (cases "exe_mode_val s = True")
      case True
      then have f4: "exe_mode_val s = True" by auto
      then show ?thesis 
      proof (cases "e1. fetch_instruction ?s' = Inl e1")
        case True
        then show ?thesis using f3
        apply exe_proof_to_decode
        apply (simp add: raise_trap_def simpler_modify_def)
        by (simp add: bind_def h1_def h2_def return_def)
      next
        case False
        then have f5: " v1. fetch_instruction ?s' = Inr v1" using fetch_instr_result_1 by blast
        then have f6: "v1 v2. fetch_instruction ?s' = Inr v1  
          ((decode_instruction v1)::(Exception list + instruction)) = Inr v2"
        using f1 fetch_instr_result_2 by blast
        then show ?thesis 
        proof (cases "annul_val ?s' = True")
          case True
          then show ?thesis using f3 f4 f6
          apply exe_proof_to_decode
          apply (simp add: set_annul_def annul_mod_def simpler_modify_def bind_def h1_def h2_def)
          apply (simp add: return_def simpler_gets_def)
          by (simp add: write_cpu_def simpler_modify_def)
        next
          case False
          then have f7: "v1 v2. fetch_instruction ?s' = Inr v1  
          ((decode_instruction v1)::(Exception list + instruction)) = Inr v2  
          (v1' v2'. fetch_instruction ?s' = Inr v1'  
          ((decode_instruction v1')::(Exception list +  instruction)) = Inr v2' 
          supported_instruction (fst v2') = True)  annul_val ?s' = False"
          using f1 f6 fetch_instr_result_2 by auto
          then have f7': "v1 v2. fetch_instruction ?s' = Inr v1  
          ((decode_instruction v1)::(Exception list + instruction)) = Inr v2  
          supported_instruction (fst v2) = True  annul_val ?s' = False"
          by auto
          then show ?thesis 
          proof (cases "v1 v2. fetch_instruction ?s' = Inr v1  
          ((decode_instruction v1)::(Exception list + instruction)) = Inr v2  
          (fst v2) = ctrl_type RETT")
            case True
            then have f8: "v1 v2. fetch_instruction ?s' = Inr v1  
            ((decode_instruction v1)::(Exception list + instruction)) = Inr v2  
            (fst v2) = ctrl_type RETT" by auto
            then show ?thesis 
            proof (cases "get_trap_set ?s' = {}")
              case True
              then have f9: "get_trap_set ?s' = {}" by auto
              then show ?thesis 
              proof (cases "get_ET (cpu_reg_val PSR ?s') = 1")
                case True
                then have f10: "get_ET (cpu_reg_val PSR ?s') = 1" by auto
                then show ?thesis 
                proof (cases "(((get_S (cpu_reg_val PSR ?s')))::word1) = 0")
                  case True
                  then show ?thesis using f3 f4 f7 f8 f9 f10
                  apply exe_proof_to_decode              
                  apply exe_proof_dispatch_rett
                  apply (simp add: raise_trap_def simpler_modify_def)
                  apply (auto simp add: execute_instr_sub1_result return_def)
                  by (simp add: case_prod_unfold)
                next
                  case False
                  then show ?thesis using f3 f4 f7 f8 f9 f10
                  apply exe_proof_to_decode
                  apply exe_proof_dispatch_rett
                  apply (simp add: raise_trap_def simpler_modify_def)
                  apply (auto simp add: execute_instr_sub1_result return_def)
                  by (simp add: case_prod_unfold)
                qed
              next
                case False
                then have f11: "v1 v2. fetch_instruction ?s' = Inr v1  
                ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
                annul_val ?s' = False 
                (fst v2) = ctrl_type RETT 
                (get_ET (cpu_reg_val PSR ?s')  1 
                (((get_S (cpu_reg_val PSR ?s')))::word1)  0 
                (get_WIM_bit (nat (((uint (get_CWP (cpu_reg_val PSR ?s'))) + 1) mod NWINDOWS)) 
                  (cpu_reg_val WIM ?s')) = 0 
                ((AND) (get_addr (snd v2) ?s') (0b00000000000000000000000000000011::word32)) = 0)"
                using f1 fetch_instr_result_2 f7' f8 by auto
                then show ?thesis using f3 f4
                proof (cases "get_trap_set ?s' = {}")
                  case True
                  then show ?thesis using f3 f4 f11
                  apply (simp add: execute_instruction_def)
                  apply (simp add: simpler_gets_def bind_def h1_def h2_def simpler_modify_def)
                  apply clarsimp
                  apply (simp add: return_def)
                  apply (simp add: bind_def h1_def h2_def Let_def)
                  apply (simp add: case_prod_unfold)   
                  apply auto
                   apply (simp add: execute_instr_sub1_result)                
                  apply (simp add: dispatch_instruction_def)
                  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)  
                  by (simp add: rett_instr_result)
                next
                  case False
                  then show ?thesis using f3 f4 f11
                  apply (simp add: execute_instruction_def)
                  apply (simp add: simpler_gets_def bind_def h1_def h2_def simpler_modify_def)
                  apply clarsimp
                  apply (simp add: return_def)
                  apply (simp add: bind_def h1_def h2_def)
                  apply (simp add: case_prod_unfold)   
                  apply (simp add: execute_instr_sub1_result)
                  apply (simp add: dispatch_instruction_def)
                  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
                  by (simp add: return_def)
                qed             
              qed
            next
              case False
              then show ?thesis using f3 f4 f7 f8
              apply exe_proof_to_decode
              apply (simp add: dispatch_instruction_def)
              apply (simp add: simpler_gets_def bind_def h1_def h2_def)
              apply (simp add: case_prod_unfold)
              by (auto simp add: execute_instr_sub1_result return_def Let_def)
            qed
          next
            case False ― ‹Instruction is not RETT›.›
            then have "v1 v2. fetch_instruction ?s' = Inr v1  
            ((decode_instruction v1)::(Exception list + instruction)) = Inr v2  
            (fst v2)  ctrl_type RETT" using f7 by auto
            then have "v1 v2. fetch_instruction ?s' = Inr v1  
            ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
            (fst v2)  ctrl_type RETT 
            supported_instruction (fst v2) = True  annul_val ?s' = False"
            using f7 by auto            
            then have "v1 v2. fetch_instruction ?s' = Inr v1  
            ((decode_instruction v1)::(Exception list + instruction)) = Inr v2 
            (fst v2)  ctrl_type RETT 
            supported_instruction (fst v2) = True  annul_val ?s' = False 
            snd (dispatch_instruction v2 ?s') = False"
            by (auto simp add: dispatch_instr_result)                   
            then show ?thesis using f3 f4
              apply exe_proof_to_decode
              apply (simp add: bind_def h1_def h2_def)
              apply (simp add: case_prod_unfold)
              by (simp add: execute_instr_sub1_result)            
          qed
        qed
      qed
    next
      case False
      then show ?thesis using f3
      apply (simp add: execute_instruction_def)
      by (simp add: exec_gets return_def)
    qed
   next
    case False
    then have "get_trap_set s  {}  
    ((reset_trap_val s)  False  get_ET (cpu_reg_val PSR s)  0)" 
      using f2 by auto
    then show ?thesis
    apply (simp add: execute_instruction_def exec_gets)
    by (simp add: execute_trap_result2)
   qed
qed

lemma dispatch_fail: 
"snd (execute_instruction() (s::(('a::len) sparc_state))) = False 
  get_trap_set s = {} 
  exe_mode_val s 
  fetch_instruction (delayed_pool_write s) = Inr v   
  ((decode_instruction v)::(Exception list + instruction)) = Inl e
  False"
using decode_instr_result_2
apply (simp add: execute_instruction_def)
apply (simp add: exec_gets bind_def)
apply clarsimp
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: simpler_modify_def return_def)
by (simp add: fail_def)

lemma no_error : "good_context s  snd (execute_instruction () s) = False"
proof -
  assume "good_context s"
  hence "snd (execute_instruction() s) = False" 
    using exe_instr_all by auto
  hence "snd (execute_instruction () s) = False" by (simp add: exec_ss2)
  thus ?thesis by assumption
qed

theorem single_step : "good_context s  NEXT s = Some (snd (fst (execute_instruction () s)))"
by (simp add: no_error next_match)

(*********************************************************************)

section ‹Privilege safty›

(*********************************************************************)

text ‹The following shows that, if the pre-state is under user mode,
  then after a singel step execution, the post-state is aslo under user mode.›

lemma write_cpu_pc_privilege: "s' = snd (fst (write_cpu w PC s)) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: write_cpu_def simpler_modify_def)
apply (simp add: cpu_reg_mod_def)
by (simp add: cpu_reg_val_def)

lemma write_cpu_npc_privilege: "s' = snd (fst (write_cpu w nPC s)) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: write_cpu_def simpler_modify_def)
apply (simp add: cpu_reg_mod_def)
by (simp add: cpu_reg_val_def)

lemma write_cpu_y_privilege: "s' = snd (fst (write_cpu w Y s)) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: write_cpu_def simpler_modify_def)
apply (simp add: cpu_reg_mod_def)
by (simp add: cpu_reg_val_def)

lemma cpu_reg_mod_y_privilege: "s' = cpu_reg_mod w Y s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
by (simp add: cpu_reg_mod_def cpu_reg_val_def)

lemma cpu_reg_mod_asr_privilege: "s' = cpu_reg_mod w (ASR r) s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
by (simp add: cpu_reg_mod_def cpu_reg_val_def)

lemma global_reg_mod_privilege: "s' = global_reg_mod w1 n w2 s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (induction n arbitrary:s)
 apply (clarsimp)
apply (auto)
apply (simp add: Let_def)
by (simp add: cpu_reg_val_def)

lemma out_reg_mod_privilege: "s' = out_reg_mod a w r s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: out_reg_mod_def Let_def)
by (simp add: cpu_reg_val_def)

lemma in_reg_mod_privilege: "s' = in_reg_mod a w r s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: in_reg_mod_def Let_def)
by (simp add: cpu_reg_val_def)

lemma user_reg_mod_privilege: 
assumes a1: " s' = user_reg_mod d (w::(('a::len) window_size)) r 
  (s::(('a::len) sparc_state))  
  (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "r = 0")
  case True
  then show ?thesis using a1
  by (simp add: user_reg_mod_def)  
next
  case False
  then have f1: "r  0" by auto
  then show ?thesis
  proof (cases "0 < r  r < 8")
    case True
    then show ?thesis using a1 f1
    apply (simp add: user_reg_mod_def)
    by (auto intro: global_reg_mod_privilege)
  next
    case False
    then have f2: "¬(0 < r  r < 8)" by auto
    then show ?thesis 
    proof (cases "7 < r  r < 16")
      case True
      then show ?thesis using a1 f1 f2
      apply (simp add: user_reg_mod_def)
      by (auto intro: out_reg_mod_privilege)
    next
      case False
      then have f3: "¬ (7 < r  r < 16)" by auto
      then show ?thesis
      proof (cases "15 < r  r < 24")
        case True
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: user_reg_mod_def)
        by (simp add: cpu_reg_val_def)
      next
        case False
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: user_reg_mod_def)
        by (auto intro: in_reg_mod_privilege)
      qed
    qed
  qed
qed

lemma write_reg_privilege: "s' = snd (fst (write_reg w1 w2 w3 
  (s::(('a::len) sparc_state)))) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: write_reg_def simpler_modify_def)
by (auto intro: user_reg_mod_privilege)

lemma set_annul_privilege: "s' = snd (fst (set_annul b s)) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: set_annul_def simpler_modify_def)
apply (simp add: annul_mod_def write_annul_def)
by (simp add: cpu_reg_val_def)

lemma set_reset_trap_privilege: "s' = snd (fst (set_reset_trap b s)) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: set_reset_trap_def simpler_modify_def)
apply (simp add: reset_trap_mod_def write_annul_def)
by (simp add: cpu_reg_val_def)

lemma empty_delayed_pool_write_privilege: "get_delayed_pool s = [] 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0 
  s' = delayed_pool_write s  
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: delayed_pool_write_def)
by (simp add: get_delayed_write_def delayed_write_all_def delayed_pool_rm_list_def)

lemma raise_trap_privilege: 
"(((get_S (cpu_reg_val PSR s)))::word1) = 0 
  s' = snd (fst (raise_trap t s))  
  (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: raise_trap_def)
apply (simp add: simpler_modify_def add_trap_set_def)
by (simp add: cpu_reg_val_def)

lemma write_cpu_tt_privilege: "s' = snd (fst (write_cpu_tt w s)) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: write_cpu_tt_def)
apply (simp add: exec_gets)
apply (simp add: write_cpu_def cpu_reg_mod_def write_tt_def)
apply (simp add: simpler_modify_def)
by (simp add: cpu_reg_val_def)

lemma emp_trap_set_privilege: "s' = emp_trap_set s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: emp_trap_set_def)
by (simp add: cpu_reg_val_def)

lemma sys_reg_mod_privilege: "s' = sys_reg_mod w r s 
   (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: sys_reg_mod_def)
by (simp add: cpu_reg_val_def)

lemma mem_mod_privilege: 
assumes a1: "s' = mem_mod a1 a2 v s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "(uint a1) = 8  (uint a1) = 10")
  case True
  then show ?thesis using a1
  apply (simp add: mem_mod_def)
  apply (simp add: Let_def)
  by (simp add: cpu_reg_val_def)
next
  case False
  then have f1: "¬((uint a1) = 8  (uint a1) = 10)" by auto
  then show ?thesis 
  proof (cases "(uint a1) = 9  (uint a1) = 11")
    case True
    then show ?thesis using a1 f1
    apply (simp add: mem_mod_def)
    apply (simp add: Let_def)
    by (simp add: cpu_reg_val_def)
  next
    case False
    then show ?thesis using a1 f1
    apply (simp add: mem_mod_def)
    by (simp add: cpu_reg_val_def)
  qed
qed

lemma mem_mod_w32_privilege: "s' = mem_mod_w32 a1 a2 b d s 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: mem_mod_w32_def)
apply (simp add: Let_def)
by (auto intro: mem_mod_privilege)

lemma add_instr_cache_privilege: "s' = add_instr_cache s addr y m 
(((get_S (cpu_reg_val PSR s)))::word1) = 0 
(((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: add_instr_cache_def)
apply (simp add: Let_def)
by (simp add: icache_mod_def cpu_reg_val_def)

lemma add_data_cache_privilege: "s' = add_data_cache s addr y m 
(((get_S (cpu_reg_val PSR s)))::word1) = 0 
(((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: add_data_cache_def)
apply (simp add: Let_def)
by (simp add: dcache_mod_def cpu_reg_val_def)

lemma memory_read_privilege: 
assumes a1: "s' = snd (memory_read asi addr s) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "uint asi = 1")
  case True
  then show ?thesis using a1 
  apply (simp add: memory_read_def)
  by (simp add: Let_def)
next
  case False
  then have f1: "uint asi  1" by auto
  then show ?thesis  
  proof (cases "uint asi = 2")
    case True 
    then show ?thesis using a1 f1
    by (simp add: memory_read_def)    
  next
    case False
    then have f2: "uint asi  2" by auto
    then show ?thesis 
    proof (cases "uint asi  {8,9}")
      case True
      then have f3: "uint asi  {8,9}" by auto
      then show ?thesis
      proof (cases "load_word_mem s addr asi = None")
        case True
        then have f4: "load_word_mem s addr asi = None" by auto
        then show ?thesis 
        using a1 f1 f2 f3 f4
        by (simp add: memory_read_def)
      next
        case False
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: memory_read_def)      
        apply auto
         apply (simp add: add_instr_cache_privilege)
        by (simp add: add_instr_cache_privilege)
      qed
    next
      case False
      then have f5: "uint asi  {8, 9}" by auto
      then show ?thesis 
        proof (cases "uint asi  {10,11}")
          case True
          then have f6: "uint asi  {10,11}" by auto
          then show ?thesis
          proof (cases "load_word_mem s addr asi = None")
            case True
            then have f7: "load_word_mem s addr asi = None" by auto
            then show ?thesis 
            using a1 f1 f2 f5 f6 f7
            by (simp add: memory_read_def)
          next
            case False
            then show ?thesis using a1 f1 f2 f5 f6
            apply (simp add: memory_read_def)      
            apply auto
             apply (simp add: add_data_cache_privilege)
            by (simp add: add_data_cache_privilege)
          qed
      next
        case False
        then have f8: "uint asi  {10,11}" by auto
        then show ?thesis
        proof (cases "uint asi = 13")
          case True
          then have f9: "uint asi = 13" by auto
          then show ?thesis 
          proof (cases "read_instr_cache s addr = None")
            case True
            then show ?thesis using a1 f1 f2 f5 f8 f9
            by (simp add: memory_read_def) 
          next
            case False
            then show ?thesis using a1 f1 f2 f5 f8 f9
            apply (simp add: memory_read_def)
            by auto
          qed
        next
          case False
          then have f10: "uint asi  13" by auto
          then show ?thesis 
          proof (cases "uint asi = 15")
            case True
            then show ?thesis using a1 f1 f2 f5 f8 f10
            apply (simp add: memory_read_def)
            apply (cases "read_data_cache s addr = None")
             by auto
          next
            case False
            then show ?thesis using a1 f1 f2 f5 f8 f10
            apply (simp add: memory_read_def) ― ‹The rest cases are easy.›
            by (simp add: Let_def)
          qed
        qed
      qed      
    qed
  qed
qed

lemma get_curr_win_privilege: "s' = snd (fst (get_curr_win() s)) 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: get_curr_win_def)
by (simp add: simpler_gets_def)

lemma load_sub2_privilege: 
assumes a1: "s' = snd (fst (load_sub2 addr asi r win w s))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "fst (memory_read asi (addr + 4)
                        (snd (fst (write_reg w win (r AND 30) s)))) =
                  None")
  case True
  then show ?thesis using a1
  apply (simp add: load_sub2_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  by (auto intro: raise_trap_privilege write_reg_privilege)
next
  case False
  then show ?thesis using a1
  apply (simp add: load_sub2_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: case_prod_unfold)
  apply clarsimp
  apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
  by (auto intro: write_reg_privilege memory_read_privilege)
qed

lemma load_sub3_privilege: 
assumes a1: "s' = snd (fst (load_sub3 instr curr_win rd asi address s))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "fst (memory_read asi address s) = None")
  case True
  then show ?thesis using a1
  apply (simp add: load_sub3_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: case_prod_unfold)
  by (auto intro: raise_trap_privilege)
next
  case False
  then have f1: "fst (memory_read asi address s)  None " by auto
  then show ?thesis 
  proof (cases "rd  0 
                          (fst instr = load_store_type LD 
                           fst instr = load_store_type LDA 
                           fst instr = load_store_type LDUH 
                           fst instr = load_store_type LDSB 
                           fst instr = load_store_type LDUB 
                           fst instr = load_store_type LDUBA 
                           fst instr = load_store_type LDSH 
                           fst instr = load_store_type LDSHA 
                           fst instr = load_store_type LDUHA 
                           fst instr = load_store_type LDSBA)")
    case True
    then show ?thesis using a1 f1
    apply (simp add: load_sub3_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: case_prod_unfold)
    apply clarsimp
    apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
    by (auto intro: write_reg_privilege memory_read_privilege)
  next 
    case False
    then show ?thesis using a1 f1
    apply (simp add: load_sub3_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: case_prod_unfold)
    apply auto
     apply (simp add: simpler_modify_def bind_def h1_def h2_def)
     apply (auto intro: load_sub2_privilege memory_read_privilege)
    apply (simp add: simpler_modify_def bind_def h1_def h2_def)
    by (auto intro: load_sub2_privilege memory_read_privilege)
  qed
qed

lemma load_sub1_privilege: 
assumes a1: "s' = snd (fst (load_sub1 instr rd s_val s))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: load_sub1_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply auto
               by (auto intro: get_curr_win_privilege raise_trap_privilege load_sub3_privilege)

lemma load_instr_privilege: "s' = snd (fst (load_instr i s))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: load_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: Let_def)
apply clarsimp
by (auto intro: get_curr_win_privilege raise_trap_privilege load_sub1_privilege)

lemma store_barrier_pending_mod_privilege: "s' = store_barrier_pending_mod b s
   (((get_S (cpu_reg_val PSR s)))::word1) = 0
   (((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: store_barrier_pending_mod_def)
apply (simp add: write_store_barrier_pending_def)
by (simp add: cpu_reg_val_def)

lemma store_word_mem_privilege: 
assumes a1: "store_word_mem s addr data byte_mask asi = Some s'  
(((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1 apply (simp add: store_word_mem_def)
apply (case_tac "virt_to_phys addr (mmu s) (mem s) = None")
apply auto
apply (case_tac "mmu_writable (get_acc_flag b) asi")
apply auto
by (simp add: mem_mod_w32_privilege)

lemma flush_instr_cache_privilege: "(((get_S (cpu_reg_val PSR s)))::word1) = 0 
s' = flush_instr_cache s 
(((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: flush_instr_cache_def)
by (simp add: cpu_reg_val_def)

lemma flush_data_cache_privilege: "(((get_S (cpu_reg_val PSR s)))::word1) = 0 
s' = flush_data_cache s 
(((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: flush_data_cache_def)
by (simp add: cpu_reg_val_def)

lemma flush_cache_all_privilege: "(((get_S (cpu_reg_val PSR s)))::word1) = 0 
s' = flush_cache_all s 
(((get_S (cpu_reg_val PSR s')))::word1) = 0"
apply (simp add: flush_cache_all_def)
by (simp add: cpu_reg_val_def)

lemma memory_write_asi_privilege: 
assumes a1: "r = memory_write_asi asi addr byte_mask data s 
  r = Some s' 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "uint asi = 1")
  case True
  then show ?thesis using a1
  apply (simp add: memory_write_asi_def)
  by (auto intro: store_word_mem_privilege)
next
  case False
  then have f1: "uint asi  1" by auto
  then show ?thesis
  proof (cases "uint asi = 2")
    case True
    then have f01: "uint asi = 2" by auto 
    then show ?thesis 
    proof (cases "uint addr = 0")
      case True
      then show ?thesis using a1 f1 f01      
      apply (simp add: memory_write_asi_def)
      apply (simp add: ccr_flush_def)
      apply (simp add: Let_def)
      apply auto
         apply (metis flush_data_cache_privilege flush_instr_cache_privilege sys_reg_mod_privilege)
        apply (metis flush_instr_cache_privilege sys_reg_mod_privilege)
       apply (metis flush_data_cache_privilege sys_reg_mod_privilege)
      by (simp add: sys_reg_mod_privilege)
    next
      case False
      then show ?thesis using a1 f1 f01
      apply (simp add: memory_write_asi_def)
      apply clarsimp
      by (metis option.distinct(1) option.sel sys_reg_mod_privilege)      
    qed      
  next
    case False
    then have f2: "uint asi  2" by auto
    then show ?thesis
    proof (cases "uint asi  {8,9}")
      case True
      then show ?thesis using a1 f1 f2
      apply (simp add: memory_write_asi_def)
      using store_word_mem_privilege add_instr_cache_privilege
      by blast    
    next
      case False
      then have f3: "uint asi  {8,9}" by auto
      then show ?thesis 
      proof (cases "uint asi  {10,11}")
        case True
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: memory_write_asi_def)
        using store_word_mem_privilege add_data_cache_privilege
        by blast 
      next
        case False
        then have f4: "uint asi  {10,11}" by auto
        then show ?thesis 
        proof (cases "uint asi = 13")
          case True
          then show ?thesis using a1 f1 f2 f3 f4
          apply (simp add: memory_write_asi_def)
          by (auto simp add: add_instr_cache_privilege)
        next
          case False
          then have f5: "uint asi  13" by auto
          then show ?thesis
          proof (cases "uint asi = 15")
            case True
            then show ?thesis using a1 f1 f2 f3 f4 f5
            apply (simp add: memory_write_asi_def)
            by (auto simp add: add_data_cache_privilege)
          next
            case False
            then have f6: "uint asi  15" by auto
            then show ?thesis
            proof (cases "uint asi = 16")
              case True
              then show ?thesis using a1
              apply (simp add: memory_write_asi_def)
              by (auto simp add: flush_instr_cache_privilege)
            next
              case False
              then have f7: "uint asi  16" by auto
              then show ?thesis
              proof (cases "uint asi = 17")
                case True
                then show ?thesis using a1
                apply (simp add: memory_write_asi_def)
                by (auto simp add: flush_data_cache_privilege)
              next
                case False
                then have f8: "uint asi  17" by auto
                then show ?thesis
                proof (cases "uint asi = 24")
                  case True
                  then show ?thesis using a1
                  apply (simp add: memory_write_asi_def)
                  by (auto simp add: flush_cache_all_privilege)
                next
                  case False
                  then have f9: "uint asi  24" by auto
                  then show ?thesis
                  proof (cases "uint asi = 25")
                    case True
                    then show ?thesis using a1
                    apply (simp add: memory_write_asi_def)
                    apply (case_tac "mmu_reg_mod (mmu s) addr data = None")
                     apply auto
                    by (simp add: cpu_reg_val_def)
                  next
                    case False
                    then have f10: "uint asi  25" by auto
                    then show ?thesis
                    proof (cases "uint asi = 28")
                      case True
                      then show ?thesis using a1
                      apply (simp add: memory_write_asi_def)
                      by (auto simp add: mem_mod_w32_privilege)
                    next
                      case False ― ‹The remaining cases are easy.›
                      then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10
                      apply (simp add: memory_write_asi_def)
                      apply (auto simp add: Let_def)
                      apply (case_tac "uint asi = 20  uint asi = 21")
                       by auto                  
                    qed
                  qed
                qed
              qed
            qed
          qed
        qed
      qed
    qed
  qed
qed

lemma memory_write_privilege: 
assumes a1: "r = memory_write asi addr byte_mask data 
  (s::(('a::len) sparc_state)) 
  r = Some s' 
  (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR 
  (s'::(('a::len) sparc_state)))))::word1) = 0"
proof -
  have "x. Some x  None" by auto
  then have "r  None" using a1
    by (simp add: r = memory_write asi addr byte_mask data s  
        r = Some s'  (get_S (cpu_reg_val PSR s)) = 0)  
  then have "s''. r = Some (store_barrier_pending_mod False s'')" using a1
    by (metis (no_types, lifting) memory_write_def option.case_eq_if) 
  then have "s''. s' = store_barrier_pending_mod False s''" using a1
    by blast    
  then have "s''. memory_write_asi asi addr byte_mask data s = Some s''  
             s' = store_barrier_pending_mod False s''"
    by (metis (no_types, lifting) assms memory_write_def not_None_eq option.case_eq_if option.sel)
  then show ?thesis using a1
    using memory_write_asi_privilege store_barrier_pending_mod_privilege by blast   
qed

lemma store_sub2_privilege: 
assumes a1: "s' = snd (fst (store_sub2 instr curr_win rd asi address s))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "memory_write asi address (st_byte_mask instr address)
                        (st_data0 instr curr_win rd address s) s =
                       None")
  case True
  then show ?thesis using a1
  apply (simp add: store_sub2_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  by (metis fst_conv raise_trap_privilege return_def snd_conv)
next
  case False
  then have f1: "¬(memory_write asi address (st_byte_mask instr address)
                        (st_data0 instr curr_win rd address s) s =
                       None)" 
    by auto
  then show ?thesis  
  proof (cases "(fst instr)  {load_store_type STD,load_store_type STDA}")
    case True
    then have f2: "(fst instr)  {load_store_type STD,load_store_type STDA}" by auto
    then show ?thesis using a1 f1
    apply (simp add: store_sub2_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
    apply (simp add: return_def)
    apply (simp add: bind_def case_prod_unfold)
    apply (simp add: simpler_modify_def)
    apply clarsimp
    apply (simp add: case_prod_unfold bind_def h1_def h2_def Let_def simpler_modify_def)
    apply (simp add: simpler_gets_def)
    apply auto
       using memory_write_privilege raise_trap_privilege apply blast
      apply (simp add: simpler_modify_def simpler_gets_def bind_def)
      apply (meson memory_write_privilege)
     using memory_write_privilege raise_trap_privilege apply blast
    by (meson memory_write_privilege)    
  next
    case False
    then show ?thesis using a1 f1
    apply (simp add: store_sub2_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
    apply clarsimp
    apply (simp add: simpler_modify_def return_def)
    by (auto intro: memory_write_privilege)
  qed
qed

lemma store_sub1_privilege: 
assumes a1: "s' = snd (fst (store_sub1 instr rd s_val 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR 
  (s'::(('a::len) sparc_state)))))::word1) = 0"
proof (cases "(fst instr = load_store_type STH  fst instr = load_store_type STHA) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s)))))::word1)  0")
  case True
  then show ?thesis using a1
  apply (simp add: store_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  using get_curr_win_privilege raise_trap_privilege by blast                
next
  case False
  then have f1: "¬((fst instr = load_store_type STH  fst instr = load_store_type STHA) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s)))))::word1)  0)"
    by auto
  then show ?thesis 
  proof (cases "(fst instr  {load_store_type ST,load_store_type STA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s)))))::word2)  0")
    case True
    then show ?thesis using a1 f1
    apply (simp add: store_sub1_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
    apply (simp add: case_prod_unfold)    
    using get_curr_win_privilege raise_trap_privilege by blast
  next
    case False
    then have f2: "¬((fst instr  {load_store_type ST,load_store_type STA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s)))))::word2)  0)"
      by auto
    then show ?thesis
    proof (cases "(fst instr  {load_store_type STD,load_store_type STDA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s)))))::word3)  0")
      case True
      then show ?thesis using a1 f1 f2
      apply (simp add: store_sub1_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: case_prod_unfold) 
      using get_curr_win_privilege raise_trap_privilege by blast
    next
      case False
      then show ?thesis using a1 f1 f2
      apply (simp add: store_sub1_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: case_prod_unfold)
      by (meson get_curr_win_privilege store_sub2_privilege)       
    qed
  qed
qed

lemma store_instr_privilege: 
assumes a1: "s' = snd (fst (store_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR 
  (s'::(('a::len) sparc_state)))))::word1) = 0"
using a1
apply (simp add: store_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def)
apply (simp add: Let_def)
using raise_trap_privilege store_sub1_privilege by blast

lemma sethi_instr_privilege: 
assumes a1: "s' = snd (fst (sethi_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: sethi_instr_def)
apply (simp add: Let_def)
apply auto
 apply (simp add: bind_def h1_def h2_def Let_def)
 apply (simp add: case_prod_unfold)
 using get_curr_win_privilege write_reg_privilege apply blast
by (simp add: return_def)

lemma nop_instr_privilege: 
assumes a1: "s' = snd (fst (nop_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: nop_instr_def)
by (simp add: return_def)

lemma ucast_0: "(((get_S w))::word1) = 0  get_S w = 0"
by simp

lemma ucast_02: "get_S w = 0  (((get_S w))::word1) = 0"
by simp

lemma ucast_s: "(((get_S w))::word1) = 0  
  (AND) w (0b00000000000000000000000010000000::word32) = 0"
  by (simp add: get_S_def split: if_splits)

lemma ucast_s2: "(AND) w 0b00000000000000000000000010000000 = 0
   (((get_S w))::word1) = 0"
by (simp add: get_S_def)

lemma update_PSR_icc_1: "w' = (AND) w (0b11111111000011111111111111111111::word32)
   (((get_S w))::word1) = 0
   (((get_S w'))::word1) = 0"
by (simp add: get_S_def word_bw_assocs(1))

lemma and_num_1048576_128: "(AND) (0b00000000000100000000000000000000::word32)
  (0b00000000000000000000000010000000::word32) = 0"
by simp

lemma and_num_2097152_128: "(AND) (0b00000000001000000000000000000000::word32)
  (0b00000000000000000000000010000000::word32) = 0"
by simp

lemma and_num_4194304_128: "(AND) (0b00000000010000000000000000000000::word32)
  (0b00000000000000000000000010000000::word32) = 0"
by simp

lemma and_num_8388608_128: "(AND) (0b00000000100000000000000000000000::word32)
  (0b00000000000000000000000010000000::word32) = 0"
by simp

lemma or_and_s: "(AND) w1 (0b00000000000000000000000010000000::word32) = 0
   (AND) w2 (0b00000000000000000000000010000000::word32) = 0
   (AND) ((OR) w1 w2) (0b00000000000000000000000010000000::word32) = 0"
by (simp add: word_ao_dist)

lemma and_or_s: 
assumes "(((get_S w1))::word1) = 0  
  (AND) w2 (0b00000000000000000000000010000000::word32) = 0"
shows "(((get_S ((OR) ((AND) w1 
  (0b11111111000011111111111111111111::word32)) w2)))::word1) = 0"
proof -
  from assms have "w1 AND 128 = 0"
    using ucast_s by blast
  then have "(w1 AND 4279238655 OR w2) AND 128 = 0"
    using assms by (metis word_ao_absorbs(6) word_ao_dist word_bw_comms(2))
  then show ?thesis
    using ucast_s2 by blast
qed 

lemma and_or_or_s:
assumes a1: "(((get_S w1))::word1) = 0  
  (AND) w2 (0b00000000000000000000000010000000::word32) = 0   
  (AND) w3 (0b00000000000000000000000010000000::word32) = 0"
shows "(((get_S ((OR) ((OR) ((AND) w1 
  (0b11111111000011111111111111111111::word32)) w2) w3)))::word1) = 0"
using and_or_s assms or_and_s ucast_s ucast_s2 by blast 

lemma and_or_or_or_s:
assumes a1: "(((get_S w1))::word1) = 0  
  (AND) w2 (0b00000000000000000000000010000000::word32) = 0   
  (AND) w3 (0b00000000000000000000000010000000::word32) = 0 
  (AND) w4 (0b00000000000000000000000010000000::word32) = 0"
shows "(((get_S ((OR) ((OR) ((OR) ((AND) w1 
  (0b11111111000011111111111111111111::word32)) w2) w3) w4)))::word1) = 0"
  using and_or_or_s assms or_and_s ucast_s ucast_s2
  by (simp add: and_or_or_s assms or_and_s ucast_s ucast_s2) 

lemma and_or_or_or_or_s:
assumes a1: "(((get_S w1))::word1) = 0  
  (AND) w2 (0b00000000000000000000000010000000::word32) = 0   
  (AND) w3 (0b00000000000000000000000010000000::word32) = 0 
  (AND) w4 (0b00000000000000000000000010000000::word32) = 0  
  (AND) w5 (0b00000000000000000000000010000000::word32) = 0"
shows "(((get_S ((OR) ((OR) ((OR) ((OR) ((AND) w1 
  (0b11111111000011111111111111111111::word32)) w2) w3) w4) w5)))::word1) = 0"
  using and_or_or_or_s assms or_and_s ucast_s ucast_s2
  by (simp add: and_or_or_or_s assms or_and_s ucast_s ucast_s2)

lemma write_cpu_PSR_icc_privilege: 
assumes a1: "s' = snd (fst (write_cpu (update_PSR_icc n_val z_val v_val c_val 
                                        (cpu_reg_val PSR s)) 
                                      PSR 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: write_cpu_def)
apply (simp add: simpler_modify_def)
apply (simp add: cpu_reg_mod_def update_PSR_icc_def)
apply (simp add: cpu_reg_val_def)
apply auto
               using update_PSR_icc_1 apply blast
              using update_PSR_icc_1 and_num_1048576_128 and_or_s apply blast
             using update_PSR_icc_1 and_num_2097152_128 and_or_s apply blast
            using update_PSR_icc_1 and_num_1048576_128 and_num_2097152_128 
            and_or_or_s apply blast
           using update_PSR_icc_1 and_num_4194304_128 and_or_s apply blast
          using update_PSR_icc_1 and_num_1048576_128 and_num_4194304_128 
          and_or_or_s apply blast
         using update_PSR_icc_1 and_num_2097152_128 and_num_4194304_128 
         and_or_or_s apply blast
        using update_PSR_icc_1 and_num_1048576_128 and_num_2097152_128 and_num_4194304_128
        and_or_or_or_s apply blast 
       using update_PSR_icc_1 and_num_8388608_128 and_or_s apply blast
      using update_PSR_icc_1 and_num_1048576_128 and_num_8388608_128 
      and_or_or_s apply blast
     using update_PSR_icc_1 and_num_2097152_128 and_num_8388608_128 
     and_or_or_s apply blast
    using update_PSR_icc_1 and_num_1048576_128 and_num_2097152_128 and_num_8388608_128
    and_or_or_or_s apply blast 
   using update_PSR_icc_1 and_num_4194304_128 and_num_8388608_128 
   and_or_or_s apply blast
  using update_PSR_icc_1 and_num_1048576_128 and_num_4194304_128 and_num_8388608_128
  and_or_or_or_s apply blast 
 using update_PSR_icc_1 and_num_2097152_128 and_num_4194304_128 and_num_8388608_128
 and_or_or_or_s apply blast 
using update_PSR_icc_1 and_num_1048576_128 and_num_2097152_128 and_num_4194304_128 
and_num_8388608_128 and_or_or_or_or_s by blast 

lemma and_num_4294967167_128: "(AND) (0b11111111111111111111111101111111::word32)
  (0b00000000000000000000000010000000::word32) = 0"
by simp

lemma s_0_word: "(((get_S ((AND) w 
  (0b11111111111111111111111101111111::word32))))::word1) = 0"
apply (simp add: get_S_def)
  using and_num_4294967167_128
  by (simp add: ac_simps)

lemma update_PSR_CWP_1: "w' = (AND) w (0b11111111111111111111111111100000::word32)
   (((get_S w))::word1) = 0
   (((get_S w'))::word1) = 0"
by (simp add: get_S_def word_bw_assocs(1))

lemma write_cpu_PSR_CWP_privilege: 
assumes a1: "s' = snd (fst (write_cpu (update_CWP cwp_val 
                                        (cpu_reg_val PSR s)) 
                                      PSR 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: write_cpu_def)
apply (simp add: simpler_modify_def)
apply (simp add: cpu_reg_mod_def)
apply (simp add: update_CWP_def)
apply (simp add: Let_def)
apply auto
apply (simp add: cpu_reg_val_def)
using s_0_word by blast

lemma logical_instr_sub1_privilege: 
assumes a1: "s' = snd (fst (logical_instr_sub1 instr_name result 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "instr_name = logic_type ANDcc 
              instr_name = logic_type ANDNcc 
              instr_name = logic_type ORcc 
              instr_name = logic_type ORNcc 
              instr_name = logic_type XORcc  instr_name = logic_type XNORcc")
  case True
  then show ?thesis using a1
  apply (simp add: logical_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: logical_new_psr_val_def)
  using write_cpu_PSR_icc_privilege by blast
next
  case False
  then show ?thesis using a1
  apply (simp add: logical_instr_sub1_def)
  by (simp add: return_def)
qed

lemma logical_instr_privilege: 
assumes a1: "s' = snd (fst (logical_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: logical_instr_def)
apply (simp add: Let_def simpler_gets_def bind_def h1_def h2_def)
apply (simp add: case_prod_unfold)
apply auto
 apply (meson get_curr_win_privilege logical_instr_sub1_privilege write_reg_privilege)
by (meson get_curr_win_privilege logical_instr_sub1_privilege write_reg_privilege)

method shift_instr_privilege_proof = (
(simp add: shift_instr_def),
(simp add: Let_def), 
(simp add: simpler_gets_def),
(simp add: bind_def h1_def h2_def Let_def case_prod_unfold),
auto,
(blast intro: get_curr_win_privilege write_reg_privilege),
(blast intro: get_curr_win_privilege write_reg_privilege)
)

lemma shift_instr_privilege: 
assumes a1: "s' = snd (fst (shift_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "(fst instr = shift_type SLL)  (get_operand_w5 ((snd instr)!3)  0)")
  case True
  then show ?thesis using a1
  by shift_instr_privilege_proof
next
  case False
  then have f1: "¬((fst instr = shift_type SLL)  (get_operand_w5 ((snd instr)!3)  0))"
    by auto
  then show ?thesis
  proof (cases "(fst instr = shift_type SRL)  (get_operand_w5 ((snd instr)!3)  0)")
    case True
    then show ?thesis using a1 f1
    by shift_instr_privilege_proof
  next
    case False
    then have f2: "¬((fst instr = shift_type SRL)  (get_operand_w5 ((snd instr)!3)  0))"
      by auto
    then show ?thesis 
    proof (cases "(fst instr = shift_type SRA)  (get_operand_w5 ((snd instr)!3)  0)")
      case True
      then show ?thesis using a1 f1 f2
      by shift_instr_privilege_proof
    next
      case False
      then show ?thesis using a1 f1 f2
      apply (simp add: shift_instr_def)
      apply (simp add: Let_def) 
      apply (simp add: simpler_gets_def)
      apply (simp add: bind_def h1_def h2_def Let_def case_prod_unfold)
      apply (simp add: return_def)
      using get_curr_win_privilege by blast
    qed
  qed
qed

lemma add_instr_sub1_privilege: 
assumes a1: "s' = snd (fst (add_instr_sub1 instr_name result rs1_val operand2 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "instr_name = arith_type ADDcc  instr_name = arith_type ADDXcc")
  case True
  then show ?thesis using a1
  apply (simp add: add_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (blast intro: write_cpu_PSR_icc_privilege)
next
  case False
  then show ?thesis using a1
  apply (simp add: add_instr_sub1_def)
  by (simp add: return_def)
qed

lemma add_instr_privilege: 
assumes a1: "s' = snd (fst (add_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: add_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
by (meson add_instr_sub1_privilege get_curr_win_privilege write_reg_privilege)

lemma sub_instr_sub1_privilege: 
assumes a1: "s' = snd (fst (sub_instr_sub1 instr_name result rs1_val operand2 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "instr_name = arith_type SUBcc  instr_name = arith_type SUBXcc")
  case True
  then show ?thesis using a1
  apply (simp add: sub_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (blast intro: write_cpu_PSR_icc_privilege)
next
  case False
  then show ?thesis using a1
  apply (simp add: sub_instr_sub1_def)
  by (simp add: return_def)
qed

lemma sub_instr_privilege: 
assumes a1: "s' = snd (fst (sub_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: sub_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
by (meson sub_instr_sub1_privilege get_curr_win_privilege write_reg_privilege)

lemma mul_instr_sub1_privilege: 
assumes a1: "s' = snd (fst (mul_instr_sub1 instr_name result  
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "instr_name  {arith_type SMULcc,arith_type UMULcc}")
  case True
  then show ?thesis using a1
  apply (simp add: mul_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (blast intro: write_cpu_PSR_icc_privilege)
next
  case False
  then show ?thesis using a1
  apply (simp add: mul_instr_sub1_def)
  by (simp add: return_def)
qed

lemma mul_instr_privilege: 
assumes a1: "s' = snd (fst (mul_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: mul_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
by (meson get_curr_win_privilege mul_instr_sub1_privilege write_cpu_y_privilege write_reg_privilege)

lemma div_write_new_val_privilege: 
assumes a1: "s' = snd (fst (div_write_new_val i result temp_V  
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "(fst i)  {arith_type UDIVcc,arith_type SDIVcc}")
  case True
  then show ?thesis using a1
  apply (simp add: div_write_new_val_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (blast intro: write_cpu_PSR_icc_privilege)
next
  case False
  then show ?thesis using a1
  apply (simp add: div_write_new_val_def)
  by (simp add: return_def)
qed

lemma div_comp_privilege: 
assumes a1: "s' = snd (fst (div_comp instr rs1 rd operand2  
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: div_comp_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
by (meson get_curr_win_privilege div_write_new_val_privilege write_reg_privilege)

lemma div_instr_privilege: 
assumes a1: "s' = snd (fst (div_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: div_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: return_def)
apply auto
 using raise_trap_privilege apply blast
using div_comp_privilege by blast

lemma save_retore_sub1_privilege: 
assumes a1: "s' = snd (fst (save_retore_sub1 result new_cwp rd 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: save_retore_sub1_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
using write_cpu_PSR_CWP_privilege write_reg_privilege by blast

method save_restore_instr_privilege_proof = (
(simp add: save_restore_instr_def),
(simp add: Let_def),
(simp add: simpler_gets_def bind_def h1_def h2_def Let_def),
(simp add: case_prod_unfold),
auto,
(blast intro: get_curr_win_privilege raise_trap_privilege),
(simp add: simpler_gets_def bind_def h1_def h2_def Let_def case_prod_unfold),
(blast intro: get_curr_win_privilege save_retore_sub1_privilege)
)

lemma save_restore_instr_privilege: 
assumes a1: "s' = snd (fst (save_restore_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "fst instr = ctrl_type SAVE")
  case True
  then have f1: "fst instr = ctrl_type SAVE" by auto
  then show ?thesis using a1
  by save_restore_instr_privilege_proof
next
  case False
  then show ?thesis using a1
  by save_restore_instr_privilege_proof
qed

lemma call_instr_privilege: 
assumes a1: "s' = snd (fst (call_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: call_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
by (meson get_curr_win_privilege write_cpu_npc_privilege write_cpu_pc_privilege write_reg_privilege)

lemma jmpl_instr_privilege: 
assumes a1: "s' = snd (fst (jmpl_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: jmpl_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply auto
 using get_curr_win_privilege raise_trap_privilege apply blast
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
by (meson get_curr_win_privilege write_cpu_npc_privilege write_cpu_pc_privilege write_reg_privilege)

lemma rett_instr_privilege: 
assumes a1: "snd (rett_instr i s) = False 
  s' = snd (fst (rett_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: rett_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply auto
 apply (simp add: case_prod_unfold)
 apply (simp add: return_def)
 apply (blast intro: raise_trap_privilege)
apply (simp add: bind_def h1_def h2_def Let_def)
by (simp add: case_prod_unfold fail_def)

method read_state_reg_instr_privilege_proof = (
(simp add: read_state_reg_instr_def),
(simp add: Let_def),
(simp add: simpler_gets_def bind_def h1_def h2_def Let_def),
(simp add: case_prod_unfold)
)

lemma read_state_reg_instr_privilege: 
assumes a1: "s' = snd (fst (read_state_reg_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "(fst instr  {sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR}  
        (fst instr = sreg_type RDASR  privileged_ASR (get_operand_w5 ((snd instr)!0))))")
  case True
  then have "(fst instr  {sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR}  
        (fst instr = sreg_type RDASR  privileged_ASR (get_operand_w5 ((snd instr)!0))))
         (((get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s))))))::word1) = 0"
    by (metis assms get_curr_win_privilege)    
  then show ?thesis using a1
  apply read_state_reg_instr_privilege_proof
  by (blast intro: raise_trap_privilege get_curr_win_privilege)
next
  case False
  then have f1: "¬((fst instr = sreg_type RDPSR 
                    fst instr = sreg_type RDWIM 
                    fst instr = sreg_type RDTBR 
                    fst instr = sreg_type RDASR  privileged_ASR (get_operand_w5 (snd instr ! 0))) 
                   (get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s))))) = 0)"
    by blast 
  then show ?thesis 
  proof (cases "illegal_instruction_ASR (get_operand_w5 ((snd instr)!0))")
    case True
    then show ?thesis using a1 f1
    apply read_state_reg_instr_privilege_proof
    by (simp add: illegal_instruction_ASR_def)    
  next
    case False
    then have f2: "¬(illegal_instruction_ASR (get_operand_w5 ((snd instr)!0)))" 
      by auto
    then show ?thesis 
    proof (cases "(get_operand_w5 ((snd instr)!1))  0")
      case True
      then have f3: "(get_operand_w5 ((snd instr)!1))  0" 
        by auto
      then show ?thesis 
      proof (cases "fst instr = sreg_type RDY")
        case True
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: read_state_reg_instr_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: case_prod_unfold)
        by (blast intro: get_curr_win_privilege write_reg_privilege)        
      next
        case False
        then have f4: "¬(fst instr = sreg_type RDY)" by auto
        then show ?thesis 
        proof (cases "fst instr = sreg_type RDASR")
          case True
          then show ?thesis using a1 f1 f2 f3 f4
          apply read_state_reg_instr_privilege_proof
          apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
          by (blast intro: get_curr_win_privilege write_reg_privilege) 
        next
          case False
          then have f5: "¬(fst instr = sreg_type RDASR)" by auto
          then show ?thesis 
          proof (cases "fst instr = sreg_type RDPSR")
            case True
            then show ?thesis using a1 f1 f2 f3 f4 f5
            apply read_state_reg_instr_privilege_proof
            by (blast intro: get_curr_win_privilege write_reg_privilege) 
          next
            case False
            then show ?thesis using a1 f1 f2 f3 f4 f5
            apply read_state_reg_instr_privilege_proof
            apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
            by (blast intro: get_curr_win_privilege write_reg_privilege) 
          qed
        qed
      qed
    next
      case False
      then show ?thesis using a1 
      apply read_state_reg_instr_privilege_proof
      apply (simp add: return_def) 
      using f1 f2 get_curr_win_privilege by blast     
    qed
  qed
qed

method write_state_reg_instr_privilege_proof = (
(simp add: write_state_reg_instr_def),
(simp add: Let_def),
(simp add: simpler_gets_def bind_def h1_def h2_def Let_def),
(simp add: case_prod_unfold)
)

lemma write_state_reg_instr_privilege: 
assumes a1: "s' = snd (fst (write_state_reg_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "fst instr = sreg_type WRY")
  case True
  then show ?thesis using a1
  apply write_state_reg_instr_privilege_proof
  apply (simp add: simpler_modify_def)
  apply (simp add: delayed_pool_add_def DELAYNUM_def)
  by (blast intro: cpu_reg_mod_y_privilege get_curr_win_privilege)
next
  case False
  then have f1: "¬(fst instr = sreg_type WRY)" by auto
  then show ?thesis
  proof (cases "fst instr = sreg_type WRASR")
    case True
    then show ?thesis
     using a1 f1
    apply write_state_reg_instr_privilege_proof
    apply (simp add: simpler_modify_def)
    apply auto
         using illegal_instruction_ASR_def apply blast
        using illegal_instruction_ASR_def apply blast
       using illegal_instruction_ASR_def apply blast
      using raise_trap_privilege get_curr_win_privilege apply blast
     apply (simp add: simpler_modify_def delayed_pool_add_def DELAYNUM_def)
     using cpu_reg_mod_asr_privilege get_curr_win_privilege apply blast
    apply (simp add: simpler_modify_def delayed_pool_add_def DELAYNUM_def)
    using cpu_reg_mod_asr_privilege get_curr_win_privilege by blast
  next
    case False
    then have f2: "¬(fst instr = sreg_type WRASR)" by auto
    have f3: "get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s)))) = 0"
      using get_curr_win_privilege a1 by (metis ucast_id)
    then show ?thesis 
    proof (cases "fst instr = sreg_type WRPSR")
      case True
      then show ?thesis using a1 f1 f2 f3
      apply write_state_reg_instr_privilege_proof
      by (metis raise_trap_privilege ucast_0)      
    next
      case False
      then have f4: "¬(fst instr = sreg_type WRPSR)" by auto
      then show ?thesis 
      proof (cases "fst instr = sreg_type WRWIM")  
        case True
        then show ?thesis using a1 f1 f2 f3 f4
        apply write_state_reg_instr_privilege_proof
        by (metis raise_trap_privilege ucast_0)  
      next
        case False
        then have f5: "¬(fst instr = sreg_type WRWIM)" by auto
        then show ?thesis using a1 f1 f2 f3 f4 f5
        apply write_state_reg_instr_privilege_proof
        by (metis raise_trap_privilege ucast_0)        
      qed
    qed
  qed
qed

lemma flush_instr_privilege: 
assumes a1: "s' = snd (fst (flush_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: flush_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def simpler_modify_def)
by (auto simp add: flush_cache_all_privilege)

lemma branch_instr_privilege: 
assumes a1: "s' = snd (fst (branch_instr instr 
  (s::(('a::len) sparc_state))))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
using a1
apply (simp add: branch_instr_def)
apply (simp add: Let_def simpler_gets_def bind_def h1_def h2_def)
apply (simp add: case_prod_unfold return_def)
by (meson set_annul_privilege write_cpu_npc_privilege write_cpu_pc_privilege)

method dispath_instr_privilege_proof = (
(simp add: dispatch_instruction_def),
(simp add: simpler_gets_def bind_def h1_def h2_def Let_def),
(simp add: Let_def)
)

lemma dispath_instr_privilege: 
assumes a1: "snd (dispatch_instruction instr s) = False 
  s' = snd (fst (dispatch_instruction instr s))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "get_trap_set s = {}")
  case True
  then have f1: "get_trap_set s = {}" by auto
  show ?thesis
  proof (cases "fst instr  {load_store_type LDSB,load_store_type LDUB,
        load_store_type LDUBA,load_store_type LDUH,load_store_type LD,
        load_store_type LDA,load_store_type LDD}")
    case True
    then show ?thesis using a1 f1
    apply dispath_instr_privilege_proof
    by (blast intro: load_instr_privilege)    
  next
    case False
    then have f2: "¬(fst instr  {load_store_type LDSB,load_store_type LDUB,
        load_store_type LDUBA,load_store_type LDUH,load_store_type LD,
        load_store_type LDA,load_store_type LDD})"
      by auto
    then show ?thesis 
    proof (cases "fst instr  {load_store_type STB,load_store_type STH,
        load_store_type ST,load_store_type STA,load_store_type STD}")
      case True
      then show ?thesis using a1 f1 f2
      apply dispath_instr_privilege_proof
      by (blast intro: store_instr_privilege) 
    next
      case False
      then have f3: "¬(fst instr  {load_store_type STB,load_store_type STH,
        load_store_type ST,load_store_type STA,load_store_type STD})"
        by auto
      then show ?thesis 
      proof (cases "fst instr  {sethi_type SETHI}")
        case True
        then show ?thesis using a1 f1 f2 f3
        apply dispath_instr_privilege_proof
        by (blast intro: sethi_instr_privilege) 
      next
        case False
        then have f4: "¬(fst instr  {sethi_type SETHI})"
          by auto
        then show ?thesis
        proof (cases "fst instr  {nop_type NOP}")
          case True
          then show ?thesis using a1 f1 f2 f3 f4
          apply dispath_instr_privilege_proof
          by (blast intro: nop_instr_privilege)
        next
          case False
          then have f5: "¬(fst instr  {nop_type NOP})" 
            by auto
          then show ?thesis
          proof (cases "fst instr  {logic_type ANDs,logic_type ANDcc,logic_type ANDN,
            logic_type ANDNcc,logic_type ORs,logic_type ORcc,logic_type ORN,
            logic_type XORs,logic_type XNOR}")
            case True
            then show ?thesis using a1 f1 f2 f3 f4 f5
            apply dispath_instr_privilege_proof
            by (blast intro: logical_instr_privilege)
          next
            case False
            then have f6: "¬(fst instr  {logic_type ANDs,logic_type ANDcc,logic_type ANDN,
            logic_type ANDNcc,logic_type ORs,logic_type ORcc,logic_type ORN,
            logic_type XORs,logic_type XNOR})"
              by auto
            show ?thesis
            proof (cases "fst instr  {shift_type SLL,shift_type SRL,shift_type SRA}")
              case True
              then show ?thesis using a1 f1 f2 f3 f4 f5 f6
              apply dispath_instr_privilege_proof
              by (blast intro: shift_instr_privilege)
            next
              case False
              then have f7: "¬(fst instr  {shift_type SLL,shift_type SRL,shift_type SRA})"
                by auto
              then show ?thesis 
              proof (cases "fst instr  {arith_type ADD,arith_type ADDcc,arith_type ADDX}")
                case True
                then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7
                apply dispath_instr_privilege_proof
                by (blast intro: add_instr_privilege)
              next
                case False
                then have f8: "¬(fst instr  {arith_type ADD,arith_type ADDcc,arith_type ADDX})"
                  by auto
                then show ?thesis
                proof (cases "fst instr  {arith_type SUB,arith_type SUBcc,arith_type SUBX}")
                  case True
                  then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8
                  apply dispath_instr_privilege_proof
                  by (blast intro: sub_instr_privilege)
                next
                  case False
                  then have f9: "¬(fst instr  {arith_type SUB,arith_type SUBcc,arith_type SUBX})"
                    by auto
                  then show ?thesis
                  proof (cases "fst instr  {arith_type UMUL,arith_type SMUL,arith_type SMULcc}")
                    case True
                    then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9
                    apply dispath_instr_privilege_proof
                    by (blast intro: mul_instr_privilege)
                  next
                    case False
                    then have f10: "¬(fst instr  {arith_type UMUL,arith_type SMUL,
                      arith_type SMULcc})"
                      by auto
                    then show ?thesis 
                    proof (cases "fst instr  {arith_type UDIV,arith_type UDIVcc,arith_type SDIV}")
                      case True
                      then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10
                      apply dispath_instr_privilege_proof
                      by (blast intro: div_instr_privilege)
                    next
                      case False
                      then have f11: "¬(fst instr  {arith_type UDIV,
                        arith_type UDIVcc,arith_type SDIV})"
                        by auto
                      then show ?thesis 
                      proof (cases "fst instr  {ctrl_type SAVE,ctrl_type RESTORE}")
                        case True
                        then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11
                        apply dispath_instr_privilege_proof
                        by (blast intro: save_restore_instr_privilege)
                      next
                        case False
                        then have f12: "¬(fst instr  {ctrl_type SAVE,ctrl_type RESTORE})"
                          by auto
                        then show ?thesis 
                        proof (cases "fst instr  {call_type CALL}")
                          case True
                          then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
                          apply dispath_instr_privilege_proof
                          by (blast intro: call_instr_privilege)
                        next
                          case False
                          then have f13: "¬(fst instr  {call_type CALL})" by auto
                          then show ?thesis
                          proof (cases "fst instr  {ctrl_type JMPL}")
                            case True
                            then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                            apply dispath_instr_privilege_proof
                            by (blast intro: jmpl_instr_privilege)
                          next
                            case False
                            then have f14: "¬(fst instr  {ctrl_type JMPL})" by auto
                            then show ?thesis 
                            proof (cases "fst instr  {ctrl_type RETT}")
                              case True
                              then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13
                                f14
                              apply dispath_instr_privilege_proof
                              by (blast intro: rett_instr_privilege)
                            next
                              case False
                              then have f15: "¬(fst instr  {ctrl_type RETT})" by auto
                              then show ?thesis 
                              proof (cases "fst instr  {sreg_type RDY,sreg_type RDPSR,
                                sreg_type RDWIM, sreg_type RDTBR}")
                                case True
                                then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 
                                f13 f14 f15
                                apply dispath_instr_privilege_proof
                                by (blast intro: read_state_reg_instr_privilege)
                              next
                                case False
                                then have f16: "¬(fst instr  {sreg_type RDY,sreg_type RDPSR,
                                sreg_type RDWIM, sreg_type RDTBR})" by auto
                                then show ?thesis
                                proof (cases "fst instr  {sreg_type WRY,sreg_type WRPSR,
                                  sreg_type WRWIM, sreg_type WRTBR}")
                                  case True
                                  then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 
                                  f13 f14 f15 f16
                                  apply dispath_instr_privilege_proof
                                  by (blast intro: write_state_reg_instr_privilege)
                                next
                                  case False
                                  then have f17: "¬(fst instr  {sreg_type WRY,sreg_type WRPSR,
                                  sreg_type WRWIM, sreg_type WRTBR})" by auto
                                  then show ?thesis
                                  proof (cases "fst instr  {load_store_type FLUSH}")
                                    case True
                                    then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 
                                    f12 f13 f14 f15 f16 f17
                                    apply dispath_instr_privilege_proof
                                    by (blast intro: flush_instr_privilege)
                                  next
                                    case False
                                    then have f18: "¬(fst instr  {load_store_type FLUSH})" by auto
                                    then show ?thesis 
                                    proof (cases "fst instr  {bicc_type BE,bicc_type BNE,
                                      bicc_type BGU,bicc_type BLE,bicc_type BL,bicc_type BGE,
                                      bicc_type BNEG,bicc_type BG,bicc_type BCS,bicc_type BLEU,
                                      bicc_type BCC,bicc_type BA,bicc_type BN}")
                                      case True
                                      then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 
                                      f12 f13 f14 f15 f16 f17 f18
                                      apply dispath_instr_privilege_proof
                                      by (blast intro: branch_instr_privilege)
                                    next
                                      case False
                                      then show ?thesis using a1 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 
                                      f12 f13 f14 f15 f16 f17 f18
                                      apply dispath_instr_privilege_proof
                                      by (simp add: fail_def)
                                    qed
                                  qed
                                qed
                              qed
                            qed
                          qed
                        qed
                      qed
                    qed
                  qed
                qed
              qed
            qed
          qed
        qed
      qed
    qed
  qed
next
  case False
  then show ?thesis using a1
  apply (simp add: dispatch_instruction_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: Let_def)
  by (simp add: return_def)
qed

lemma execute_instr_sub1_privilege: 
assumes a1: "snd (execute_instr_sub1 i s) = False 
  s' = snd (fst (execute_instr_sub1 i s))
   (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "get_trap_set s = {}  fst i  {call_type CALL,ctrl_type RETT,ctrl_type JMPL,
                                   bicc_type BE,bicc_type BNE,bicc_type BGU,
                                   bicc_type BLE,bicc_type BL,bicc_type BGE,
                                   bicc_type BNEG,bicc_type BG,
                                   bicc_type BCS,bicc_type BLEU,bicc_type BCC,
                                   bicc_type BA,bicc_type BN}")
  case True
  then show ?thesis using a1
  apply (simp add: execute_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold return_def)
  by (auto intro: write_cpu_pc_privilege write_cpu_npc_privilege)
next
  case False
  then show ?thesis using a1
  apply (simp add: execute_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold return_def)
  by auto
qed

text ‹
  Assume that there is no delayed_write› and 
  there is no traps to be executed.
  If an instruction is executed as a user,
  the privilege will not be changed to supervisor after 
  the execution.›
theorem safe_privilege : 
assumes a1: "get_delayed_pool s = []  get_trap_set s = {} 
  snd (execute_instruction() s) = False 
  s' = snd (fst (execute_instruction() s))  
  (((get_S (cpu_reg_val PSR s)))::word1) = 0"
shows "(((get_S (cpu_reg_val PSR s')))::word1) = 0"
proof (cases "exe_mode_val s")
  case True   
  then have f2: "exe_mode_val s = True" by auto
  then show ?thesis
  proof (cases "e. fetch_instruction (delayed_pool_write s) = Inl e")
    case True
    then have f3: "e. fetch_instruction (delayed_pool_write s) = Inl e"
      by auto
    then have f4: "¬ (v. fetch_instruction (delayed_pool_write s) = Inr v)" 
      using fetch_instr_result_3 by auto
    then show ?thesis using a1 f2 f3 raise_trap_result empty_delayed_pool_write_privilege raise_trap_privilege        
    apply (simp add: execute_instruction_def)
    apply (simp add: exec_gets return_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
    apply (simp add: simpler_modify_def)
    apply clarsimp
    apply (simp add: case_prod_unfold)
    by (blast intro: empty_delayed_pool_write_privilege raise_trap_privilege)      
  next
    case False
    then have f5: "v. fetch_instruction (delayed_pool_write s) = Inr v"
      using fetch_instr_result_1 by blast
    then have f6: "v. fetch_instruction (delayed_pool_write s) = Inr v 
    ¬ (e. ((decode_instruction v)::(Exception list + instruction)) = Inl e)"
      using a1 f2 dispatch_fail by blast 
    then have f7: "v. fetch_instruction (delayed_pool_write s) = Inr v 
    (v1. ((decode_instruction v)::(Exception list + instruction)) = Inr v1)"
      using decode_instr_result_4 by auto 
    then show ?thesis
    proof (cases "annul_val (delayed_pool_write s)")
      case True
      then show ?thesis using  a1 f2 f7           
      apply (simp add: execute_instruction_def)
      apply (simp add: exec_gets return_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: simpler_modify_def)
      apply clarsimp
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: case_prod_unfold)
      by (auto intro: empty_delayed_pool_write_privilege 
      set_annul_privilege write_cpu_npc_privilege write_cpu_pc_privilege)
    next 
      case False
      then show ?thesis using  a1 f2 f7 
      apply (simp add: execute_instruction_def)
      apply (simp add: exec_gets return_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: simpler_modify_def)
      apply clarsimp
      apply (simp add: bind_def h1_def h2_def Let_def)
      apply (simp add: case_prod_unfold)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: simpler_modify_def return_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: case_prod_unfold)
      by (auto intro: empty_delayed_pool_write_privilege dispath_instr_privilege 
         execute_instr_sub1_privilege)        
    qed
  qed    
next
  case False
  then show ?thesis using a1 
  apply (simp add: execute_instruction_def)
  by (simp add: simpler_gets_def bind_def h1_def h2_def Let_def return_def) 
qed

(*********************************************************************)

section ‹Single step non-interference property.›

(*********************************************************************)

definition user_accessible:: "('a::len) sparc_state  phys_address  bool" where
"user_accessible s pa  va p. (virt_to_phys va (mmu s) (mem s)) = Some p 
  mmu_readable (get_acc_flag (snd p)) 10 
  (fst p) = pa" ― ‹Passing asi = 8› is the same.›

lemma user_accessible_8: 
assumes a1: "mmu_readable (get_acc_flag (snd p)) 8"
shows "mmu_readable (get_acc_flag (snd p)) 10"
using a1 by (simp add: mmu_readable_def)

definition mem_equal:: "('a) sparc_state  ('a) sparc_state  
  phys_address  bool" where
"mem_equal s1 s2 pa 
  (mem s1) 8 (pa AND 68719476732) = (mem s2) 8 (pa AND 68719476732) 
  (mem s1) 8 ((pa AND 68719476732) + 1) = (mem s2) 8 ((pa AND 68719476732) + 1) 
  (mem s1) 8 ((pa AND 68719476732) + 2) = (mem s2) 8 ((pa AND 68719476732) + 2) 
  (mem s1) 8 ((pa AND 68719476732) + 3) = (mem s2) 8 ((pa AND 68719476732) + 3) 
  (mem s1) 9 (pa AND 68719476732) = (mem s2) 9 (pa AND 68719476732) 
  (mem s1) 9 ((pa AND 68719476732) + 1) = (mem s2) 9 ((pa AND 68719476732) + 1) 
  (mem s1) 9 ((pa AND 68719476732) + 2) = (mem s2) 9 ((pa AND 68719476732) + 2) 
  (mem s1) 9 ((pa AND 68719476732) + 3) = (mem s2) 9 ((pa AND 68719476732) + 3) 
  (mem s1) 10 (pa AND 68719476732) = (mem s2) 10 (pa AND 68719476732) 
  (mem s1) 10 ((pa AND 68719476732) + 1) = (mem s2) 10 ((pa AND 68719476732) + 1) 
  (mem s1) 10 ((pa AND 68719476732) + 2) = (mem s2) 10 ((pa AND 68719476732) + 2) 
  (mem s1) 10 ((pa AND 68719476732) + 3) = (mem s2) 10 ((pa AND 68719476732) + 3) 
  (mem s1) 11 (pa AND 68719476732) = (mem s2) 11 (pa AND 68719476732) 
  (mem s1) 11 ((pa AND 68719476732) + 1) = (mem s2) 11 ((pa AND 68719476732) + 1) 
  (mem s1) 11 ((pa AND 68719476732) + 2) = (mem s2) 11 ((pa AND 68719476732) + 2) 
  (mem s1) 11 ((pa AND 68719476732) + 3) = (mem s2) 11 ((pa AND 68719476732) + 3)"

text low_equal› defines the equivalence relation over two sparc
states that is an analogy to the =L relation over memory contexts
in the traditional non-interference theorem.›

definition low_equal:: "('a::len) sparc_state  ('a) sparc_state  bool" where
"low_equal s1 s2  
  (cpu_reg s1) = (cpu_reg s2) 
  (user_reg s1) = (user_reg s2) 
  (sys_reg s1) = (sys_reg s2)   
  (va. (virt_to_phys va (mmu s1) (mem s1)) = (virt_to_phys va (mmu s2) (mem s2))) 
  (pa. (user_accessible s1 pa)  mem_equal s1 s2 pa)   
  (mmu s1) = (mmu s2)  
  (state_var s1) = (state_var s2) 
  (traps s1) = (traps s2) 
  (undef s1) = (undef s2)
" 

lemma low_equal_com: "low_equal s1 s2  low_equal s2 s1"
apply (simp add: low_equal_def)
apply (simp add: mem_equal_def user_accessible_def)
by metis

lemma non_exe_mode_equal: "exe_mode_val s = False 
get_trap_set s = {} 
Some t = NEXT s  
t = s"
apply (simp add: NEXT_def execute_instruction_def)
apply auto
by (simp add: simpler_gets_def bind_def h1_def h2_def Let_def return_def)

lemma exe_mode_low_equal:
assumes a1: "low_equal s1 s2"
shows " exe_mode_val s1 =  exe_mode_val s2"
using a1 apply (simp add: low_equal_def)
by (simp add: exe_mode_val_def)

lemma mem_val_mod_state: "mem_val_alt asi a s = mem_val_alt asi a 
(scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef)"
apply (simp add: mem_val_alt_def)
by (simp add: Let_def)

lemma mem_val_w32_mod_state: "mem_val_w32 asi a s = mem_val_w32 asi a 
(scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef)"
apply (simp add: mem_val_w32_def)
apply (simp add: Let_def)
by (metis mem_val_mod_state)

lemma load_word_mem_mod_state: "load_word_mem s addr asi = load_word_mem 
(scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr asi"
apply (simp add: load_word_mem_def)
apply (case_tac "virt_to_phys addr (mmu s) (mem s) = None")
 apply auto
by (auto simp add: mem_val_w32_mod_state)

lemma load_word_mem2_mod_state: 
"fst (case load_word_mem s addr asi of None  (None, s)
      | Some w  (Some w, add_data_cache s addr w 15)) =
 fst (case load_word_mem (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr asi of
         None  (None, (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef))
      | Some w  (Some w, add_data_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr w 15))"
proof (cases "load_word_mem s addr asi = None")
  case True
  then have "load_word_mem s addr asi = None 
    load_word_mem (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr asi = None"
    using load_word_mem_mod_state by metis
  then show ?thesis by auto
next
  case False
  then have "w. load_word_mem s addr asi = Some w" by auto
  then have "w. load_word_mem s addr asi = Some w  
    load_word_mem (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr asi = Some w"
  using load_word_mem_mod_state by metis
  then show ?thesis by auto
qed

lemma load_word_mem3_mod_state: 
"fst (case load_word_mem s addr asi of None  (None, s)
      | Some w  (Some w, add_instr_cache s addr w 15)) =
 fst (case load_word_mem (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr asi of
         None  (None, (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef))
      | Some w  (Some w, add_instr_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr w 15))"
proof (cases "load_word_mem s addr asi = None")
  case True
  then have "load_word_mem s addr asi = None 
    load_word_mem (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr asi = None"
    using load_word_mem_mod_state by metis
  then show ?thesis by auto
next
  case False
  then have "w. load_word_mem s addr asi = Some w" by auto
  then have "w. load_word_mem s addr asi = Some w  
    load_word_mem (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr asi = Some w"
  using load_word_mem_mod_state by metis
  then show ?thesis by auto
qed

lemma read_dcache_mod_state: "read_data_cache s addr = read_data_cache 
(scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr"
apply (simp add: read_data_cache_def)
by (simp add: dcache_val_def)

lemma read_dcache2_mod_state: 
"fst (case read_data_cache s addr of None  (None, s)
      | Some w  (Some w, s)) =
 fst (case read_data_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr of
         None  (None, (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef))
      | Some w  (Some w, (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef)))"
proof (cases "read_data_cache s addr = None")
  case True
  then have "read_data_cache s addr = None 
    read_data_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr = None"
    using read_dcache_mod_state by metis
  then show ?thesis by auto    
next
  case False
  then have "w. read_data_cache s addr = Some w" by auto
  then have "w. read_data_cache s addr = Some w  
    read_data_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr = Some w"
    using read_dcache_mod_state by metis
  then show ?thesis by auto
qed

lemma read_icache_mod_state: "read_instr_cache s addr = read_instr_cache 
(scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr"
apply (simp add: read_instr_cache_def)
by (simp add: icache_val_def)

lemma read_icache2_mod_state: 
"fst (case read_instr_cache s addr of None  (None, s)
      | Some w  (Some w, s)) =
 fst (case read_instr_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr of
         None  (None, (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef))
      | Some w  (Some w, (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef)))"
proof (cases "read_instr_cache s addr = None")
  case True
  then have "read_instr_cache s addr = None 
    read_instr_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr = None"
    using read_icache_mod_state by metis
  then show ?thesis by auto    
next
  case False
  then have "w. read_instr_cache s addr = Some w" by auto
  then have "w. read_instr_cache s addr = Some w  
    read_instr_cache (scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) addr = Some w"
    using read_icache_mod_state by metis
  then show ?thesis by auto
qed

lemma mem_read_mod_state: "fst (memory_read asi addr s) =
fst (memory_read asi addr 
(scpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef))"
apply (simp add: memory_read_def)
apply (case_tac "uint asi = 1")
 apply (simp add: Let_def)
 apply (metis load_word_mem_mod_state option.distinct(1))
apply (case_tac "uint asi = 2")
 apply (simp add: Let_def)
 apply (simp add: sys_reg_val_def)
apply (case_tac "uint asi  {8,9}")
 apply (simp add: Let_def)
 apply (simp add: load_word_mem3_mod_state)
 apply (simp add: load_word_mem_mod_state)
apply (case_tac "uint asi  {10,11}")
 apply (simp add: Let_def)
 apply (simp add: load_word_mem2_mod_state)
 apply (simp add: load_word_mem_mod_state)
apply (case_tac "uint asi = 13")
 apply (simp add: Let_def)
 apply (simp add: read_icache2_mod_state)
apply (case_tac "uint asi = 15")
 apply (simp add: Let_def)
 apply (simp add: read_dcache2_mod_state)
apply (case_tac "uint asi = 25")
 apply (simp add: Let_def)
apply (case_tac "uint asi = 28")
 apply (simp add: Let_def)
 apply (simp add: mem_val_w32_mod_state)
by (simp add: Let_def)

lemma insert_trap_mem: "fst (memory_read asi addr s) =
fst (memory_read asi addr (straps := new_traps))"
proof -
  have "fst (memory_read asi addr s) =
    fst (memory_read asi addr 
      (scpu_reg := (cpu_reg s),
         user_reg := (user_reg s),
         dwrite := (dwrite s),
         state_var := (state_var s),
         traps := new_traps,
         undef := (undef s)))"
    using mem_read_mod_state by blast
    then show ?thesis by auto
qed

lemma cpu_reg_mod_mem: "fst (memory_read asi addr s) =
fst (memory_read asi addr (scpu_reg := new_cpu_reg))"
proof -
  have "fst (memory_read asi addr s) =
    fst (memory_read asi addr 
      (scpu_reg := new_cpu_reg,
         user_reg := (user_reg s),
         dwrite := (dwrite s),
         state_var := (state_var s),
         traps := (traps s),
         undef := (undef s)))"
    using mem_read_mod_state by blast
    then show ?thesis by auto
qed

lemma user_reg_mod_mem: "fst (memory_read asi addr s) =
fst (memory_read asi addr (suser_reg := new_user_reg))"
proof -
  have "fst (memory_read asi addr s) =
    fst (memory_read asi addr 
      (scpu_reg := (cpu_reg s),
         user_reg := new_user_reg,
         dwrite := (dwrite s),
         state_var := (state_var s),
         traps := (traps s),
         undef := (undef s)))"
    using mem_read_mod_state by blast
    then show ?thesis by auto
qed

lemma annul_mem: "fst (memory_read asi addr s) =
fst (memory_read asi addr 
(sstate_var := new_state_var,
   cpu_reg := new_cpu_reg))"
proof -
  have "fst (memory_read asi addr s) =
    fst (memory_read asi addr 
      (scpu_reg := new_cpu_reg,
         user_reg := (user_reg s),
         dwrite := (dwrite s),
         state_var := new_state_var,
         traps := (traps s),
         undef := (undef s)))"
    using mem_read_mod_state by blast
  then have "fst (memory_read asi addr s) =
    fst (memory_read asi addr 
      (scpu_reg := new_cpu_reg,
         state_var := new_state_var))"
    by auto        
  then show ?thesis 
    by (metis Sparc_State.sparc_state.surjective Sparc_State.sparc_state.update_convs(1) Sparc_State.sparc_state.update_convs(8))
qed

lemma state_var_mod_mem: "fst (memory_read asi addr s) =
fst (memory_read asi addr (sstate_var := new_state_var))"
proof -
  have "fst (memory_read asi addr s) =
    fst (memory_read asi addr 
      (scpu_reg := (cpu_reg s),
         user_reg := (user_reg s),
         dwrite := (dwrite s),
         state_var := new_state_var,
         traps := (traps s),
         undef := (undef s)))"
    using mem_read_mod_state by blast
    then show ?thesis by auto
qed

lemma mod_state_low_equal: "low_equal s1 s2 
t1 = (s1cpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) 
t2 = (s2cpu_reg := new_cpu_reg,
   user_reg := new_user_reg,
   dwrite := new_dwrite,
   state_var := new_state_var,
   traps := new_traps,
   undef := new_undef) 
low_equal t1 t2"
apply (simp add: low_equal_def)
apply clarsimp
apply (simp add: mem_equal_def)
by (simp add: user_accessible_def)

lemma user_reg_state_mod_low_equal: 
assumes a1: "low_equal s1 s2            
t1 = (s1user_reg := new_user_reg) 
t2 = (s2user_reg := new_user_reg)"
shows "low_equal t1 t2"
proof -
  have "low_equal s1 s2 
t1 = (s1cpu_reg := (cpu_reg s1),
   user_reg := new_user_reg,
   dwrite := (dwrite s1),
   state_var := (state_var s1),
   traps := (traps s1),
   undef := (undef s1)) 
t2 = (s2cpu_reg := (cpu_reg s2),
   user_reg := new_user_reg,
   dwrite := (dwrite s2),
   state_var := (state_var s2),
   traps := (traps s2),
   undef := (undef s2)) 
low_equal t1 t2"
    using mod_state_low_equal apply (simp add: low_equal_def)    
    apply (simp add: user_accessible_def mem_equal_def)
    by clarsimp
  then show ?thesis using a1
  by clarsimp
qed

lemma mod_trap_low_equal: 
assumes a1: "low_equal s1 s2            
t1 = (s1traps := new_traps) 
t2 = (s2traps := new_traps)"
shows "low_equal t1 t2"
proof -
  have "low_equal s1 s2 
t1 = (s1cpu_reg := (cpu_reg s1),
   user_reg := (user_reg s1),
   dwrite := (dwrite s1),
   state_var := (state_var s1),
   traps := new_traps,
   undef := (undef s1)) 
t2 = (s2cpu_reg := (cpu_reg s2),
   user_reg := (user_reg s2),
   dwrite := (dwrite s2),
   state_var := (state_var s2),
   traps := new_traps,
   undef := (undef s2)) 
low_equal t1 t2"
    using mod_state_low_equal apply (simp add: low_equal_def)
    apply (simp add: user_accessible_def mem_equal_def)
    by clarsimp
  then show ?thesis using a1
  by clarsimp
qed

lemma state_var_low_equal: "low_equal s1 s2 
state_var s1 = state_var s2"
by (simp add: low_equal_def)

lemma state_var2_low_equal: 
assumes a1: "low_equal s1 s2            
t1 = (s1state_var := new_state_var) 
t2 = (s2state_var := new_state_var)"
shows "low_equal t1 t2"
proof -
  have "low_equal s1 s2 
t1 = (s1cpu_reg := (cpu_reg s1),
   user_reg := (user_reg s1),
   dwrite := (dwrite s1),
   state_var := new_state_var,
   traps := (traps s1),
   undef := (undef s1)) 
t2 = (s2cpu_reg := (cpu_reg s2),
   user_reg := (user_reg s2),
   dwrite := (dwrite s2),
   state_var := new_state_var,
   traps := (traps s2),
   undef := (undef s2)) 
low_equal t1 t2"
    using mod_state_low_equal apply (simp add: low_equal_def)
    apply (simp add: user_accessible_def mem_equal_def)
    by clarsimp   
  then show ?thesis using a1
  by clarsimp
qed

lemma traps_low_equal: "low_equal s1 s2  traps s1 = traps s2"
by (simp add: low_equal_def)

lemma s_low_equal: "low_equal s1 s2 
(get_S (cpu_reg_val PSR s1)) = (get_S (cpu_reg_val PSR s2))"
by (simp add: low_equal_def cpu_reg_val_def)

lemma cpu_reg_val_low_equal: "low_equal s1 s2 
(cpu_reg_val cr s1) = (cpu_reg_val cr s2)"
by (simp add: cpu_reg_val_def low_equal_def)

lemma get_curr_win_low_equal: "low_equal s1 s2 
(fst (fst (get_curr_win () s1))) = (fst (fst (get_curr_win () s2)))"
apply (simp add: low_equal_def)
apply (simp add: get_curr_win_def cpu_reg_val_def get_CWP_def)
by (simp add: simpler_gets_def)

lemma get_curr_win2_low_equal: "low_equal s1 s2 
t1 = (snd (fst (get_curr_win () s1))) 
t2 = (snd (fst (get_curr_win () s2))) 
low_equal t1 t2"
apply (simp add: low_equal_def)
apply (simp add: get_curr_win_def cpu_reg_val_def get_CWP_def)
by (auto simp add: simpler_gets_def)

lemma get_curr_win3_low_equal: "low_equal s1 s2 
(traps (snd (fst (get_curr_win () s1)))) =
(traps (snd (fst (get_curr_win () s2))))"
using low_equal_def get_curr_win2_low_equal by blast

lemma get_addr_low_equal: "low_equal s1 s2 
((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3) =
((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word3) 
((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2) =
((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word2) 
((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word1) =
((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word1)"
apply (simp add: low_equal_def)
apply (simp add: get_curr_win_def cpu_reg_val_def get_CWP_def)
apply (simp add: simpler_gets_def get_addr_def user_reg_val_def)
apply (simp add: Let_def )
apply (simp add: get_CWP_def cpu_reg_val_def get_operand2_def)
by (simp add: user_reg_val_def)

lemma get_addr2_low_equal: "low_equal s1 s2 
get_addr (snd instr) (snd (fst (get_curr_win () s1))) =
get_addr (snd instr) (snd (fst (get_curr_win () s2)))"
apply (simp add: low_equal_def)
apply (simp add: get_curr_win_def cpu_reg_val_def get_CWP_def)
apply (simp add: simpler_gets_def get_addr_def user_reg_val_def)
apply (simp add: Let_def )
apply (simp add: get_CWP_def cpu_reg_val_def get_operand2_def)
by (simp add: user_reg_val_def)

lemma sys_reg_low_equal: "low_equal s1 s2 
sys_reg s1 = sys_reg s2"
by (simp add: low_equal_def)

lemma user_reg_low_equal: "low_equal s1 s2 
user_reg s1 = user_reg s2"
by (simp add: low_equal_def)

lemma user_reg_val_low_equal: "low_equal s1 s2 
user_reg_val win ur s1 = user_reg_val win ur s2"
apply (simp add: user_reg_val_def)
by (simp add: user_reg_low_equal)

lemma get_operand2_low_equal: "low_equal s1 s2 
get_operand2 op_list s1 = get_operand2 op_list s2"
apply (simp add: get_operand2_def)
apply (simp add: cpu_reg_val_low_equal)
apply auto
apply (simp add: user_reg_val_def)
using user_reg_low_equal by fastforce

lemma mem_val_mod_cache: "mem_val_alt asi a s = 
mem_val_alt asi a (scache := new_cache)"
apply (simp add: mem_val_alt_def)
by (simp add: Let_def)

lemma mem_val_w32_mod_cache: "mem_val_w32 asi a s = 
mem_val_w32 asi a (scache := new_cache)"
apply (simp add: mem_val_w32_def)
apply (simp add: Let_def)
by (metis mem_val_mod_cache)

lemma load_word_mem_mod_cache: 
"load_word_mem s addr asi =
load_word_mem (scache := new_cache) addr asi"
apply (simp add: load_word_mem_def)
apply (case_tac "virt_to_phys addr (mmu s) (mem s) = None")
 apply auto
by (simp add: mem_val_w32_mod_cache)

lemma memory_read_8_mod_cache:
"fst (memory_read 8 addr s) = fst (memory_read 8 addr (scache := new_cache))"
apply (simp add: memory_read_def)
apply (case_tac "sys_reg s CCR AND 1  0")
 apply auto
 apply (simp add: option.case_eq_if load_word_mem_mod_cache)
 apply (auto intro: load_word_mem_mod_cache)
 apply (metis load_word_mem_mod_cache option.distinct(1))
by (metis load_word_mem_mod_cache option.distinct(1))

lemma memory_read_10_mod_cache:
"fst (memory_read 10 addr s) = fst (memory_read 10 addr (scache := new_cache))"
apply (simp add: memory_read_def)
apply (case_tac "sys_reg s CCR AND 1  0")
 apply auto
 apply (simp add: option.case_eq_if load_word_mem_mod_cache)
 apply (auto intro: load_word_mem_mod_cache)
 apply (metis load_word_mem_mod_cache option.distinct(1))
by (metis load_word_mem_mod_cache option.distinct(1))

lemma mem_equal_mod_cache: "mem_equal s1 s2 pa 
mem_equal (s1cache := new_cache1) (s2cache := new_cache2) pa"
by (simp add: mem_equal_def)

lemma user_accessible_mod_cache: "user_accessible (scache := new_cache) pa =
user_accessible s pa"
by (simp add: user_accessible_def)

lemma mem_equal_mod_user_reg: "mem_equal s1 s2 pa 
mem_equal (s1user_reg := new_user_reg1) (s2user_reg := user_reg2) pa"
by (simp add: mem_equal_def)

lemma user_accessible_mod_user_reg: "user_accessible (suser_reg := new_user_reg) pa =
user_accessible s pa"
by (simp add: user_accessible_def)

lemma mem_equal_mod_cpu_reg: "mem_equal s1 s2 pa 
mem_equal (s1cpu_reg := new_cpu1) (s2cpu_reg := cpu_reg2) pa"
by (simp add: mem_equal_def)

lemma user_accessible_mod_cpu_reg: "user_accessible (scpu_reg := new_cpu_reg) pa =
user_accessible s pa"
by (simp add: user_accessible_def)

lemma mem_equal_mod_trap: "mem_equal s1 s2 pa 
mem_equal (s1traps := new_traps1) (s2traps := traps2) pa"
by (simp add: mem_equal_def)

lemma user_accessible_mod_trap: "user_accessible (straps := new_traps) pa =
user_accessible s pa"
by (simp add: user_accessible_def)

lemma mem_equal_annul: "mem_equal s1 s2 pa 
mem_equal (s1state_var := new_state_var,
   cpu_reg := new_cpu_reg) (s2state_var := new_state_var2,
   cpu_reg := new_cpu_reg2) pa"
by (simp add: mem_equal_def)

lemma user_accessible_annul: "user_accessible (sstate_var := new_state_var, 
  cpu_reg := new_cpu_reg) pa =
user_accessible s pa"
by (simp add: user_accessible_def)

lemma mem_val_alt_10_mem_equal_0: "mem_equal s1 s2 pa 
mem_val_alt 10 (pa AND 68719476732) s1 = mem_val_alt 10 (pa AND 68719476732) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_mem_equal_1: "mem_equal s1 s2 pa 
mem_val_alt 10 ((pa AND 68719476732) + 1) s1 = mem_val_alt 10 ((pa AND 68719476732) + 1) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_mem_equal_2: "mem_equal s1 s2 pa 
mem_val_alt 10 ((pa AND 68719476732) + 2) s1 = mem_val_alt 10 ((pa AND 68719476732) + 2) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_mem_equal_3: "mem_equal s1 s2 pa 
mem_val_alt 10 ((pa AND 68719476732) + 3) s1 = mem_val_alt 10 ((pa AND 68719476732) + 3) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_mem_equal: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 10 (pa AND 68719476732) s1 = mem_val_alt 10 (pa AND 68719476732) s2 
  mem_val_alt 10 ((pa AND 68719476732) + 1) s1 = mem_val_alt 10 ((pa AND 68719476732) + 1) s2 
  mem_val_alt 10 ((pa AND 68719476732) + 2) s1 = mem_val_alt 10 ((pa AND 68719476732) + 2) s2 
  mem_val_alt 10 ((pa AND 68719476732) + 3) s1 = mem_val_alt 10 ((pa AND 68719476732) + 3) s2"
using mem_val_alt_10_mem_equal_0 mem_val_alt_10_mem_equal_1
mem_val_alt_10_mem_equal_2 mem_val_alt_10_mem_equal_3 a1
by blast

lemma mem_val_w32_10_mem_equal: 
assumes a1: "mem_equal s1 s2 a"
shows "mem_val_w32 10 a s1 = mem_val_w32 10 a s2"
apply (simp add: mem_val_w32_def)
apply (simp add: Let_def)
using mem_val_alt_10_mem_equal a1 apply auto
        apply fastforce 
       apply fastforce
      apply fastforce
     apply fastforce
    apply fastforce
   apply fastforce
  apply fastforce
 apply fastforce
by fastforce

lemma mem_val_alt_8_mem_equal_0: "mem_equal s1 s2 pa 
mem_val_alt 8 (pa AND 68719476732) s1 = mem_val_alt 8 (pa AND 68719476732) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_mem_equal_1: "mem_equal s1 s2 pa 
mem_val_alt 8 ((pa AND 68719476732) + 1) s1 = mem_val_alt 8 ((pa AND 68719476732) + 1) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_mem_equal_2: "mem_equal s1 s2 pa 
mem_val_alt 8 ((pa AND 68719476732) + 2) s1 = mem_val_alt 8 ((pa AND 68719476732) + 2) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_mem_equal_3: "mem_equal s1 s2 pa 
mem_val_alt 8 ((pa AND 68719476732) + 3) s1 = mem_val_alt 8 ((pa AND 68719476732) + 3) s2"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_mem_equal: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 8 (pa AND 68719476732) s1 = mem_val_alt 8 (pa AND 68719476732) s2 
  mem_val_alt 8 ((pa AND 68719476732) + 1) s1 = mem_val_alt 8 ((pa AND 68719476732) + 1) s2 
  mem_val_alt 8 ((pa AND 68719476732) + 2) s1 = mem_val_alt 8 ((pa AND 68719476732) + 2) s2 
  mem_val_alt 8 ((pa AND 68719476732) + 3) s1 = mem_val_alt 8 ((pa AND 68719476732) + 3) s2"
using mem_val_alt_8_mem_equal_0 mem_val_alt_8_mem_equal_1
mem_val_alt_8_mem_equal_2 mem_val_alt_8_mem_equal_3 a1
by blast

lemma mem_val_w32_8_mem_equal: 
assumes a1: "mem_equal s1 s2 a"
shows "mem_val_w32 8 a s1 = mem_val_w32 8 a s2"
apply (simp add: mem_val_w32_def)
apply (simp add: Let_def)
using mem_val_alt_8_mem_equal a1 apply auto
        apply fastforce 
       apply fastforce
      apply fastforce
     apply fastforce
    apply fastforce
   apply fastforce
  apply fastforce
 apply fastforce
by fastforce

lemma load_word_mem_10_low_equal: 
assumes a1: "low_equal s1 s2"
shows "load_word_mem s1 address 10 = load_word_mem s2 address 10"
using a1 apply (simp add: low_equal_def load_word_mem_def)
apply clarsimp
apply (case_tac "virt_to_phys address (mmu s2) (mem s2) = None")
 apply auto
 apply (simp add: user_accessible_def)
 using mem_val_w32_10_mem_equal apply blast 
apply (simp add: user_accessible_def)
using mem_val_w32_10_mem_equal by blast 

lemma load_word_mem_8_low_equal: 
assumes a1: "low_equal s1 s2"
shows "load_word_mem s1 address 8 = load_word_mem s2 address 8"
using a1 apply (simp add: low_equal_def load_word_mem_def)
apply clarsimp
apply (case_tac "virt_to_phys address (mmu s2) (mem s2) = None")
 apply auto
 apply (simp add: user_accessible_def)
 using mem_val_w32_8_mem_equal user_accessible_8 apply fastforce
apply (simp add: user_accessible_def)
using mem_val_w32_8_mem_equal user_accessible_8 by fastforce

lemma mem_read_low_equal: 
assumes a1: "low_equal s1 s2  asi  {8,10}"
shows "fst (memory_read asi address s1) = fst (memory_read asi address s2)"
proof (cases "asi = 8")
  case True
  then show ?thesis using a1 
  apply (simp add: low_equal_def)
  apply (simp add: memory_read_def)
  using a1 load_word_mem_8_low_equal apply auto
  apply (simp add: option.case_eq_if)
  by (simp add: option.case_eq_if)
next
  case False
  then have "asi = 10" using a1 by auto
  then show ?thesis using a1
  apply (simp add: low_equal_def)
  apply (simp add: memory_read_def)
  using a1 load_word_mem_10_low_equal apply auto
  apply (simp add: option.case_eq_if)
  by (simp add: option.case_eq_if)
qed 

lemma read_mem_pc_low_equal: 
assumes a1: "low_equal s1 s2"
shows "fst (memory_read 8 (cpu_reg_val PC s1) s1) = 
fst (memory_read 8 (cpu_reg_val PC s2) s2)"
proof -
  have f2: "cpu_reg_val PC s1 = cpu_reg_val PC s2" using a1 
    by (simp add: low_equal_def cpu_reg_val_def)
  then show ?thesis using a1 f2 mem_read_low_equal
    by auto
qed

lemma dcache_mod_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = dcache_mod c v s1 
t2 = dcache_mod c v s2"
shows "low_equal t1 t2"
using a1 apply (simp add: low_equal_def)
apply (simp add: dcache_mod_def)
apply auto
 apply (simp add: user_accessible_mod_cache mem_equal_mod_cache)
by (simp add: user_accessible_mod_cache mem_equal_mod_cache)

lemma add_data_cache_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = add_data_cache s1 address w bm 
t2 = add_data_cache s2 address w bm"
shows "low_equal t1 t2"
using a1 apply (simp add: add_data_cache_def)
apply (case_tac "bm AND 8 >> 3 = 1")
 apply auto
 apply (case_tac "bm AND 4 >> 2 = 1")
  apply auto
  apply (case_tac "bm AND 2 >> Suc 0 = 1")
   apply auto
   apply (case_tac "bm AND 1 = 1")
    apply auto
    apply (meson dcache_mod_low_equal)
   apply (meson dcache_mod_low_equal)
  apply (case_tac "bm AND 1 = 1")
   apply auto
   apply (meson dcache_mod_low_equal)
  apply (meson dcache_mod_low_equal)
 apply (case_tac "bm AND 2 >> Suc 0 = 1")
  apply auto
  apply (case_tac "bm AND 1 = 1")
   apply auto
   apply (meson dcache_mod_low_equal)
  apply (meson dcache_mod_low_equal)
 apply (case_tac "bm AND 1 = 1")
  apply auto
  apply (meson dcache_mod_low_equal)
 apply (meson dcache_mod_low_equal)
apply (case_tac "bm AND 4 >> 2 = 1")
 apply auto
 apply (case_tac "bm AND 2 >> Suc 0 = 1")
  apply auto
  apply (case_tac "bm AND 1 = 1")
   apply auto
   apply (meson dcache_mod_low_equal)
  apply (meson dcache_mod_low_equal)
 apply (case_tac "bm AND 1 = 1")
  apply auto
  apply (meson dcache_mod_low_equal)
 apply (meson dcache_mod_low_equal)
apply (case_tac "bm AND 2 >> Suc 0 = 1")
 apply auto
 apply (case_tac "bm AND 1 = 1")
  apply auto
  apply (meson dcache_mod_low_equal)
 apply (meson dcache_mod_low_equal)
by (meson dcache_mod_low_equal)

lemma mem_read2_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (memory_read (10::word8) address s1) 
t2 = snd (memory_read (10::word8) address s2)"
shows "low_equal t1 t2"
  using a1 apply (simp add: memory_read_def)
  using a1 apply (auto simp add: sys_reg_low_equal mod_2_eq_odd)
  using a1 apply (simp add: load_word_mem_10_low_equal)
  apply (auto split: option.splits)
  using add_data_cache_low_equal apply force
  using add_data_cache_low_equal apply force
  done

lemma mem_read_delayed_write_low_equal:
assumes a1: "low_equal s1 s2  get_delayed_pool s1 = []  get_delayed_pool s2 = []"
shows "fst (memory_read 8 (cpu_reg_val PC (delayed_pool_write s1)) (delayed_pool_write s1)) =
fst (memory_read 8 (cpu_reg_val PC (delayed_pool_write s2)) (delayed_pool_write s2))"
using a1 apply (simp add: delayed_pool_write_def)
apply (simp add: Let_def)
apply (simp add: get_delayed_write_def)
by (simp add: read_mem_pc_low_equal)

lemma global_reg_mod_low_equal: 
assumes a1: "low_equal s1 s2
t1 = (global_reg_mod w n rd s1) 
t2 = (global_reg_mod w n rd s2)"
shows "low_equal t1 t2"
using a1 apply (induction n arbitrary: s1 s2)
 apply clarsimp
apply auto
apply (simp add: Let_def)
apply (simp add: user_reg_low_equal)
using user_reg_state_mod_low_equal by blast

lemma out_reg_mod_low_equal: 
assumes a1: "low_equal s1 s2
t1 = (out_reg_mod w curr_win rd s1) 
t2 = (out_reg_mod w curr_win rd s2)"
shows "low_equal t1 t2"
using a1 apply (simp add: out_reg_mod_def Let_def)
apply auto
 apply (simp add: user_reg_low_equal)
 using user_reg_state_mod_low_equal apply fastforce
apply (simp add: user_reg_low_equal)
using user_reg_state_mod_low_equal by blast

lemma in_reg_mod_low_equal: 
assumes a1: "low_equal s1 s2
t1 = (in_reg_mod w curr_win rd s1) 
t2 = (in_reg_mod w curr_win rd s2)"
shows "low_equal t1 t2"
using a1 apply (simp add: in_reg_mod_def Let_def)
apply auto
 apply (simp add: user_reg_low_equal)
 using user_reg_state_mod_low_equal apply fastforce
apply (simp add: user_reg_low_equal)
using user_reg_state_mod_low_equal by blast

lemma user_reg_mod_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = user_reg_mod w curr_win rd s1  t2 = user_reg_mod w curr_win rd s2"
shows "low_equal t1 t2"
proof (cases "rd = 0")
  case True
  then show ?thesis using a1
  by (simp add: user_reg_mod_def)
next
  case False
  then have f1: "rd  0" by auto
  then show ?thesis 
  proof (cases "0 < rd  rd < 8")
    case True
    then show ?thesis using a1 f1
    apply (simp add: user_reg_mod_def)
    using global_reg_mod_low_equal by blast    
  next
    case False
    then have f2: "¬ (0 < rd  rd < 8)" by auto
    then show ?thesis  
    proof (cases "7 < rd  rd < 16")
      case True
      then show ?thesis using a1 f1 f2
      apply (simp add: user_reg_mod_def)
      by (auto intro: out_reg_mod_low_equal)
    next
      case False
      then have f3: "¬ (7 < rd  rd < 16)" by auto      
      then show ?thesis 
      proof (cases "15 < rd  rd < 24")
        case True
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: user_reg_mod_def)
        apply (simp add: low_equal_def)
        apply clarsimp
        by (simp add: user_accessible_mod_user_reg mem_equal_mod_user_reg)     
      next
        case False
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: user_reg_mod_def)
        by (auto intro: in_reg_mod_low_equal)
      qed
    qed
  qed
qed

lemma virt_to_phys_low_equal: "low_equal s1 s2 
virt_to_phys addr (mmu s1) (mem s1) = virt_to_phys addr (mmu s2) (mem s2)"
by (auto simp add: low_equal_def)

lemma write_reg_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = (snd (fst (write_reg w curr_win rd s1))) 
t2 = (snd (fst (write_reg w curr_win rd s2)))"
shows "low_equal t1 t2"
using a1 apply (simp add: write_reg_def)
apply (simp add: simpler_modify_def)
by (auto intro: user_reg_mod_low_equal)

lemma write_cpu_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (write_cpu w cr s1)) 
t2 = (snd (fst (write_cpu w cr s2)))"
shows "low_equal t1 t2"
using a1
apply (simp add: write_cpu_def simpler_modify_def)
apply (simp add: cpu_reg_mod_def)
apply (simp add: low_equal_def)
using user_accessible_mod_cpu_reg mem_equal_mod_cpu_reg
by metis

lemma cpu_reg_mod_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = cpu_reg_mod w cr s1 
t2 = cpu_reg_mod w cr s2"
shows "low_equal t1 t2"
using a1
apply (simp add: cpu_reg_mod_def)
apply (simp add: low_equal_def)
using user_accessible_mod_cpu_reg mem_equal_mod_cpu_reg
by metis

lemma load_sub2_low_equal:
assumes a1: "low_equal s1 s2 
t1 = (snd (fst (load_sub2 address 10 rd curr_win w s1))) 
t2 = (snd (fst (load_sub2 address 10 rd curr_win w s2)))"
shows "low_equal t1 t2"
proof (cases "fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s1)))) = None")
  case True
  then have f0: "fst (memory_read 10 (address + 4) 
        (snd (fst (write_reg w curr_win (rd AND 30) s1)))) = None" by auto
  have f1: "low_equal (snd (fst (write_reg w curr_win (rd AND 30) s1)))
          (snd (fst (write_reg w curr_win (rd AND 30) s2)))"
    using a1 by (auto intro: write_reg_low_equal)
  then have "fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s1)))) = None 
        fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s1)))) =
        fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s2))))"
    using f0 by (blast intro: mem_read_low_equal)
  then have "fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s1)))) = None 
        fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s2)))) = None"
    by auto
  then show ?thesis using a1
  apply (simp add: load_sub2_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply (simp add: raise_trap_def add_trap_set_def)
  apply (simp add: simpler_modify_def)
  using f1 apply (simp add: traps_low_equal)
  using f1 by (auto intro: mod_trap_low_equal)
next
  case False
  then have f2: "fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s1))))  None"
    by auto
  have f3: "low_equal (snd (fst (write_reg w curr_win (rd AND 30) s1)))
          (snd (fst (write_reg w curr_win (rd AND 30) s2)))"
    using a1 by (auto intro: write_reg_low_equal)
  then have f4: "fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s1)))) =
        fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s2))))"
    using f2 by (blast intro: mem_read_low_equal)
  then have "fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s1))))  None 
        fst (memory_read 10 (address + 4)
        (snd (fst (write_reg w curr_win (rd AND 30) s2))))  None"
    using f2 by auto
  then show ?thesis using a1
  apply (simp add: load_sub2_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply clarsimp
  apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
  using f4 apply clarsimp
  using f3 by (auto intro: mem_read2_low_equal write_reg_low_equal)
qed

lemma load_sub3_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (load_sub3 instr curr_win rd (10::word8) address s1)) 
t2 = snd (fst (load_sub3 instr curr_win rd (10::word8) address s2))"
shows "low_equal t1 t2"
proof (cases "fst (memory_read 10 address s1) = None")
  case True
  then have "fst (memory_read 10 address s1) = None 
    fst (memory_read 10 address s2) = None"
    using a1 by (auto simp add: mem_read_low_equal)
  then show ?thesis using a1
  apply (simp add: load_sub3_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: case_prod_unfold)
  apply (simp add: raise_trap_def add_trap_set_def)
  apply (simp add: simpler_modify_def)
  apply (auto simp add: traps_low_equal)
  by (auto intro: mod_trap_low_equal)
next
  case False
  then have f1: "fst (memory_read 10 address s1)  None  
    fst (memory_read 10 address s2)  None"
    using a1 by (auto simp add: mem_read_low_equal)  
  then show ?thesis 
  proof (cases "rd  0 
                          (fst instr = load_store_type LD 
                           fst instr = load_store_type LDA 
                           fst instr = load_store_type LDUH 
                           fst instr = load_store_type LDSB 
                           fst instr = load_store_type LDUB 
                           fst instr = load_store_type LDUBA 
                           fst instr = load_store_type LDSH 
                           fst instr = load_store_type LDSHA 
                           fst instr = load_store_type LDUHA 
                           fst instr = load_store_type LDSBA)")
    case True
    then show ?thesis using a1 f1
    apply (simp add: load_sub3_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: case_prod_unfold)
    apply clarsimp
    apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
    apply (simp add: mem_read_low_equal)
    by (meson mem_read2_low_equal write_reg_low_equal)
  next
    case False
    then show ?thesis using a1 f1
    apply (simp add: load_sub3_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: case_prod_unfold)
    apply clarsimp
    apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
    apply (simp add: mem_read_low_equal)
    by (meson load_sub2_low_equal mem_read2_low_equal)
  qed
qed

lemma ld_asi_user:
"(fst instr = load_store_type LDSB 
fst instr = load_store_type LDUB 
fst instr = load_store_type LDUH  
fst instr = load_store_type LD  
fst instr = load_store_type LDD)  
ld_asi instr 0 = 10"
apply (simp add: ld_asi_def)
by auto

lemma load_sub1_low_equal: 
assumes a1: "low_equal s1 s2 
(fst instr = load_store_type LDSB 
fst instr = load_store_type LDUB 
fst instr = load_store_type LDUH 
fst instr = load_store_type LD  
fst instr = load_store_type LDD) 
t1 = snd (fst (load_sub1 instr rd 0 s1))  
t2 = snd (fst (load_sub1 instr rd 0 s2))" 
shows "low_equal t1 t2"
proof (cases "(fst instr = load_store_type LDD  fst instr = load_store_type LDDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3)  0 
                       (fst instr = load_store_type LD  fst instr = load_store_type LDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2)  0 
                       (fst instr = load_store_type LDUH 
                        fst instr = load_store_type LDUHA 
                        fst instr = load_store_type LDSH  fst instr = load_store_type LDSHA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word1)  0")
  case True
  then have "((fst instr = load_store_type LDD  fst instr = load_store_type LDDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3)  0 
                       (fst instr = load_store_type LD  fst instr = load_store_type LDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2)  0 
                       (fst instr = load_store_type LDUH 
                        fst instr = load_store_type LDUHA 
                        fst instr = load_store_type LDSH  fst instr = load_store_type LDSHA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word1)  0) 
            ((fst instr = load_store_type LDD  fst instr = load_store_type LDDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word3)  0 
                       (fst instr = load_store_type LD  fst instr = load_store_type LDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word2)  0 
                       (fst instr = load_store_type LDUH 
                        fst instr = load_store_type LDUHA 
                        fst instr = load_store_type LDSH  fst instr = load_store_type LDSHA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word1)  0)"
    by (metis (mono_tags, lifting) assms get_addr_low_equal)    
  then show ?thesis using a1
  apply (simp add: load_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply (simp add: raise_trap_def add_trap_set_def)
  apply (simp add: simpler_modify_def)
  apply clarsimp
  apply (simp add: get_curr_win3_low_equal)
  by (auto intro: get_curr_win2_low_equal mod_trap_low_equal)
next
  case False
  then have f1: "¬ ((fst instr = load_store_type LDD  fst instr = load_store_type LDDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3)  0 
                       (fst instr = load_store_type LD  fst instr = load_store_type LDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2)  0 
                       (fst instr = load_store_type LDUH 
                        fst instr = load_store_type LDUHA 
                        fst instr = load_store_type LDSH  fst instr = load_store_type LDSHA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word1)  0) 
            ¬ ((fst instr = load_store_type LDD  fst instr = load_store_type LDDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word3)  0 
                       (fst instr = load_store_type LD  fst instr = load_store_type LDA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word2)  0 
                       (fst instr = load_store_type LDUH 
                        fst instr = load_store_type LDUHA 
                        fst instr = load_store_type LDSH  fst instr = load_store_type LDSHA) 
                       ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word1)  0)"
    by (metis assms get_addr_low_equal)    
  show ?thesis  
  proof -
    have "low_equal s1 s2  
          low_equal (snd (fst (get_curr_win () s1))) 
                    (snd (fst (get_curr_win () s2)))"
      using get_curr_win2_low_equal by auto
    then have f2: "low_equal s1 s2 
      low_equal (snd (fst (load_sub3 instr (fst (fst (get_curr_win () s2))) rd 10
                    (get_addr (snd instr) (snd (fst (get_curr_win () s2))))
                    (snd (fst (get_curr_win () s1)))))) 
                (snd (fst (load_sub3 instr (fst (fst (get_curr_win () s2))) rd 10
                    (get_addr (snd instr) (snd (fst (get_curr_win () s2))))
                    (snd (fst (get_curr_win () s2))))))"
      using load_sub3_low_equal by blast 
    show ?thesis using a1
    unfolding load_sub1_def simpler_gets_def bind_def h1_def h2_def Let_def case_prod_unfold
    using f1 f2 apply clarsimp
    by (simp add: get_addr2_low_equal get_curr_win_low_equal ld_asi_user)
  qed
qed

lemma load_instr_low_equal: 
assumes a1: "low_equal s1 s2 
(fst instr = load_store_type LDSB 
fst instr = load_store_type LDUB 
fst instr = load_store_type LDUBA 
fst instr = load_store_type LDUH 
fst instr = load_store_type LD  
fst instr = load_store_type LDA  
fst instr = load_store_type LDD) 
(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
t1 = snd (fst (load_instr instr s1))  t2 = snd (fst (load_instr instr s2))"
shows "low_equal t1 t2"
proof -
  have "get_S (cpu_reg_val PSR s1) = 0  get_S (cpu_reg_val PSR s2) = 0"
    using a1 by (simp add: ucast_id) 
  then show ?thesis using a1
  apply (simp add: load_instr_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: Let_def)
  apply clarsimp
  apply (simp add: raise_trap_def add_trap_set_def)
  apply (simp add: simpler_modify_def)
  apply (simp add: traps_low_equal)
  by (auto intro: mod_trap_low_equal load_sub1_low_equal)
qed

lemma st_data0_low_equal: "low_equal s1 s2 
st_data0 instr curr_win rd addr s1 = st_data0 instr curr_win rd addr s2"
apply (simp add: st_data0_def)
by (simp add: user_reg_val_def low_equal_def)

lemma store_word_mem_low_equal_none: "low_equal s1 s2 
store_word_mem (add_data_cache s1 addr data bm) addr data bm 10 = None 
store_word_mem (add_data_cache s2 addr data bm) addr data bm 10 = None"
apply (simp add: store_word_mem_def)
proof -
  assume a1: "low_equal s1 s2"
  assume a2: "(case virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) of None  None | Some pair  if mmu_writable (get_acc_flag (snd pair)) 10 then Some (mem_mod_w32 10 (fst pair) bm data (add_data_cache s1 addr data bm)) else None) = None"
  have f3: "(if mmu_writable (get_acc_flag (snd (v1_2 (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (v1_2 (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s2 addr data bm)) else None) = (case Some (v1_2 (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))) of None  if mmu_writable (get_acc_flag (snd (v1_2 (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (v1_2 (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s1 addr data bm)) else None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None)"
    by auto
  obtain pp :: "(word36 × word8) option  word36 × word8" where
    f4: "virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) = None  virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) = Some (pp (virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))))"
    by (metis (no_types) option.exhaust)
  have f5: "virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) = virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))"
    using a1 by (meson add_data_cache_low_equal virt_to_phys_low_equal)
  { assume "Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s1 addr data bm))  (case Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s1 addr data bm)) else None)"
    then have "None = (if mmu_writable (get_acc_flag (snd (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s2 addr data bm)) else None)"
      by fastforce
    moreover
    { assume "(if mmu_writable (get_acc_flag (snd (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s2 addr data bm)) else None)  (case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None)"
      then have "(case Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))) of None  if mmu_writable (get_acc_flag (snd (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s1 addr data bm)) else None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None)  (case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None)"
        using f3 by simp
      then have "Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))  virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))  (if mmu_writable (get_acc_flag (snd (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s1 addr data bm)) else None)  None"
      proof -
        have "(case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  if mmu_writable (get_acc_flag (snd (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s1 addr data bm)) else None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None) = (case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None)  Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))  virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))  (if mmu_writable (get_acc_flag (snd (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s1 addr data bm)) else None)  None"
          by simp
        then show ?thesis
          using (case Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))) of None  if mmu_writable (get_acc_flag (snd (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)))))) 10 then Some (mem_mod_w32 10 (fst (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))) bm data (add_data_cache s1 addr data bm)) else None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None)  (case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None) by force
      qed
      moreover
      { assume "Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))  virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))"
        then have "virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))  Some (pp (virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))))"
          using f5 by simp }
      ultimately have "virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))  Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))  virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))  Some (pp (virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))))"
        using a2 by force }
    ultimately have "virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) = Some (pp (virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))))  virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) = Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))  (case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None) = None"
      by fastforce }
  then have "virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) = Some (pp (virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm))))  virt_to_phys addr (mmu (add_data_cache s1 addr data bm)) (mem (add_data_cache s1 addr data bm)) = Some (pp (virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm))))  (case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None) = None"
    using a2 by force
  then show "(case virt_to_phys addr (mmu (add_data_cache s2 addr data bm)) (mem (add_data_cache s2 addr data bm)) of None  None | Some p  if mmu_writable (get_acc_flag (snd p)) 10 then Some (mem_mod_w32 10 (fst p) bm data (add_data_cache s2 addr data bm)) else None) = None"
    using f5 f4 by force
qed

lemma memory_write_asi_low_equal_none: "low_equal s1 s2 
memory_write_asi 10 addr bm data s1 = None 
memory_write_asi 10 addr bm data s2 = None"
apply (simp add: memory_write_asi_def)
by (simp add: store_word_mem_low_equal_none)

lemma memory_write_low_equal_none: "low_equal s1 s2 
memory_write 10 addr bm data s1 = None 
memory_write 10 addr bm data s2 = None"
apply (simp add: memory_write_def)
by (metis map_option_case memory_write_asi_low_equal_none option.map_disc_iff)

lemma memory_write_low_equal_none2: "low_equal s1 s2 
memory_write 10 addr bm data s2 = None 
memory_write 10 addr bm data s1 = None"
apply (simp add: memory_write_def)
by (metis low_equal_com memory_write_def memory_write_low_equal_none)

lemma mem_context_val_9_unchanged:
"mem_context_val 9 addr1 (mem s1) =
mem_context_val 9 addr1
              ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))"
apply (simp add: mem_context_val_def)
by (simp add: Let_def)

lemma mem_context_val_w32_9_unchanged:
"mem_context_val_w32 9 addr1 (mem s1) =
mem_context_val_w32 9 addr1
              ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))"
apply (simp add: mem_context_val_w32_def)
apply (simp add: Let_def)
by (metis mem_context_val_9_unchanged)

lemma ptd_lookup_unchanged_4: 
"ptd_lookup va ptp (mem s1) 4 = 
ptd_lookup va ptp ((mem s1)(10 := mem s1 10(addr  val), 
                            11 := (mem s1 11)(addr := None))) 4"
by auto

lemma ptd_lookup_unchanged_3: 
"ptd_lookup va ptp (mem s1) 3 = 
ptd_lookup va ptp ((mem s1)(10 := mem s1 10(addr  val), 
                            11 := (mem s1 11)(addr := None))) 3"
proof (cases "mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) (mem s1) = None")
  case True
  then have "mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) (mem s1) = None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36)
           ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) = None"
    using mem_context_val_w32_9_unchanged by metis    
  then show ?thesis 
  by auto  
next
  case False
  then have "mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) (mem s1)  None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None"
    using mem_context_val_w32_9_unchanged by metis
  then have "mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) (mem s1)  None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None 
    (y. (mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) (mem s1) = Some y)  
    (mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 12))::word6))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))= Some y))"
    using mem_context_val_w32_9_unchanged by metis
  then show ?thesis 
  apply auto
  by (simp add: Let_def)
qed

lemma ptd_lookup_unchanged_2: 
"ptd_lookup va ptp (mem s1) 2 = 
ptd_lookup va ptp ((mem s1)(10 := mem s1 10(addr  val), 
                            11 := (mem s1 11)(addr := None))) 2"
proof (cases "mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) (mem s1) = None")
  case True
  then have "mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) (mem s1) = None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36)
           ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) = None"
    using mem_context_val_w32_9_unchanged by metis    
  then show ?thesis 
  by auto  
next
  case False
  then have "mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) (mem s1)  None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None"
    using mem_context_val_w32_9_unchanged by metis
  then have "mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) (mem s1)  None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None 
    (y. (mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) (mem s1) = Some y)  
    (mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 18))::word6))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))= Some y))"
    using mem_context_val_w32_9_unchanged by metis
  then show ?thesis 
  apply auto
  using ptd_lookup_unchanged_3   
  unfolding Let_def
  by auto
qed

lemma ptd_lookup_unchanged_1: 
"ptd_lookup va ptp (mem s1) 1 = 
ptd_lookup va ptp ((mem s1)(10 := mem s1 10(addr  val), 
                            11 := (mem s1 11)(addr := None))) 1"
proof (cases "mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) (mem s1) = None")
  case True
  then have "mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) (mem s1) = None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36)
           ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) = None"
    using mem_context_val_w32_9_unchanged by metis    
  then show ?thesis 
  by auto  
next
  case False
  then have "mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) (mem s1)  None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None"
    using mem_context_val_w32_9_unchanged by metis
  then have "mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) (mem s1)  None 
    mem_context_val_w32 9 ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None 
    (y. (mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) (mem s1) = Some y)  
    (mem_context_val_w32 9 
    ((ucast (ptp OR ((ucast ((ucast (va >> 24))::word8))::word32)))::word36) 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))= Some y))"
    using mem_context_val_w32_9_unchanged by metis
  then show ?thesis 
  apply auto
  using ptd_lookup_unchanged_2   
  unfolding Let_def
  proof -
    fix y :: word32
    have "(y AND 3  0  y AND 3 = 0  (y AND 3  1  ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) = None)  (y AND 3 = 1  y AND 3  2  None = Some ((ucast (ucast (y >> 8)::word24) << 12) OR (ucast (ucast va::word12)::word36), ucast y::word8)))  (y AND 3 = 0  (y AND 3  1  (y AND 3  0  ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1) = None)  (y AND 3 = 0  (y AND 3  1  ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) = ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1))  (y AND 3 = 1  (y AND 3  2  ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1) = Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y))  (y AND 3 = 2  ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1) = None))))  (y AND 3 = 1  (y AND 3  2  (y AND 3  0  None = Some ((ucast (ucast (y >> 8)::word24) << 12) OR (ucast (ucast va::word12)::word36), ucast y::word8))  (y AND 3 = 0  (y AND 3  1  ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) = Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y))  (y AND 3 = 1  y AND 3 = 2  None = Some ((ucast (ucast (y >> 8)::word24) << 12) OR (ucast (ucast va::word12)::word36), ucast y::word8))))  (y AND 3 = 2  y AND 3 = 0  (y AND 3  1  ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) = None)  (y AND 3 = 1  y AND 3  2  None = Some ((ucast (ucast (y >> 8)::word24) << 12) OR (ucast (ucast va::word12)::word36), ucast y::word8)))))  (w. mem s1 w = ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) w)"
      by (metis (no_types) One_nat_def Suc_1 Suc_eq_plus1 ptd_lookup_unchanged_2)
    then show "(if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None) = (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None)"
    proof -
      have f1: "2 = Suc 0 + 1"
        by (metis One_nat_def Suc_1 Suc_eq_plus1)
      { assume "y AND 3 = 1"
        moreover
        { assume "y AND 3 = 1  (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None)  (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None)"
          have "y AND 3 = 1  (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None)  ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1)  (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None) = (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None)"
            by presburger
          moreover
          { assume "y AND 3 = 1  (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None)  ptd_lookup va (y AND 4294967292) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) (Suc 0 + 1)"
            then have "y AND 3 = 1  (if y AND 3 = 0 then None else if y AND 3 = 1 then ptd_lookup va (y AND 4294967292) (mem s1) (Suc 0 + 1) else if y AND 3 = 2 then Some ((ucast (ucast (y >> 8)::word24) << 12) OR ucast (ucast va::word12), ucast y) else None)  ptd_lookup va (y AND 4294967292) (mem s1) 2"
              by (metis One_nat_def Suc_1 Suc_eq_plus1 ptd_lookup_unchanged_2)
            then have ?thesis
              using f1 by auto }
          ultimately have ?thesis
            by blast }
        ultimately have ?thesis
          by blast }
      then show ?thesis
        by presburger
    qed  
  qed
qed

lemma virt_to_phys_unchanged_sub1: 
assumes a1: "(let context_table_entry = (v1 >> 11 << 11) OR (v2 AND 511 << 2)
  in Let (mem_context_val_w32 (word_of_int 9) (ucast context_table_entry) (mem s1))
    (case_option None (λlvl1_page_table. ptd_lookup va lvl1_page_table (mem s1) 1))) =
 (let context_table_entry = (v1 >> 11 << 11) OR (v2 AND 511 << 2)
  in Let (mem_context_val_w32 (word_of_int 9) (ucast context_table_entry) (mem s2))
    (case_option None (λlvl1_page_table. ptd_lookup va lvl1_page_table (mem s2) 1)))"
shows "(let context_table_entry = (v1 >> 11 << 11) OR (v2 AND 511 << 2)
  in Let (mem_context_val_w32 (word_of_int 9) (ucast context_table_entry)
    ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))))
     (case_option None (λlvl1_page_table. ptd_lookup va lvl1_page_table
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1))) =
 (let context_table_entry = (v1 >> 11 << 11) OR (v2 AND 511 << 2)
  in Let (mem_context_val_w32 (word_of_int 9) (ucast context_table_entry)
    ((mem s2)(10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))))
     (case_option None (λlvl1_page_table. ptd_lookup va lvl1_page_table
      ((mem s2)(10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) 1)))"
proof -
  from a1 have 
   "(case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) (mem s1) of
     None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s1) 1) =
    (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) (mem s2) of
     None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s2) 1)" 
     unfolding Let_def by auto
  then have "(case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) 
     ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of
     None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s1) 1) =
    (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) 
     ((mem s2)(10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of
     None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s2) 1)"
    using mem_context_val_w32_9_unchanged
    by (metis word_numeral_alt) 
 then have "(case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) 
     ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of
     None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table 
      ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1) =
    (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) 
     ((mem s2)(10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of
     None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table 
     ((mem s2)(10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) 1)"   
    using ptd_lookup_unchanged_1
    proof -
      obtain ww :: "word32 option  word32" where
        f1: "z. (z = None  z = Some (ww z))  (z  None  (w. z  Some w))"
        by moura
      then have f2: "(mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) = None  mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) = Some (ww (mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))))))  (mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None  (w. mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  Some w))"
        by blast
      then have f3: "(case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some w  ptd_lookup va w ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1)  None  (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some w  ptd_lookup va w ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1) = (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some w  ptd_lookup va w (mem s1) 1)"
        by (metis (no_types) val va s1 ptp addr. ptd_lookup va ptp (mem s1) 1 = ptd_lookup va ptp ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1 option.case(2) option.simps(4))
      have f4: "mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) = Some (ww (mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None)))))  mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) = Some (ww (mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))))  (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some w  ptd_lookup va w ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1) = (case Some (ww (mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))))) of None  None | Some w  ptd_lookup va w ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) 1)"
        by (metis (no_types) (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s1) 1) = (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s2) 1) val va s1 ptp addr. ptd_lookup va ptp (mem s1) 1 = ptd_lookup va ptp ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1 option.case(2))
      have f5: "(mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) = None  mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) = Some (ww (mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))))))  (mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None)))  None  (w. mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None)))  Some w))"
        using f1 by blast
      { assume "(case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some w  ptd_lookup va w ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1)  (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of None  None | Some w  ptd_lookup va w ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) 1)"
        { assume "(case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of None  None | Some w  ptd_lookup va w (mem s2) 1)  None  (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of None  None | Some w  ptd_lookup va w (mem s2) 1)  None"
          then have "(case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of None  None | Some w  ptd_lookup va w (mem s2) 1)  None  mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)))  None"
            by (metis (no_types) (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s1) 1) = (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s2) 1) option.simps(4))
          then have ?thesis
            using f5 f4 f2 by force }
        then have ?thesis
          using f5 f3 by (metis (no_types) (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) of None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s1) 1) = (case mem_context_val_w32 (word_of_int 9) (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2) (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s2) 1) val va s1 ptp addr. ptd_lookup va ptp (mem s1) 1 = ptd_lookup va ptp ((mem s1) (10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) 1 option.case(2) option.simps(4)) }
      then show ?thesis
        by blast
    qed
 then show ?thesis 
  unfolding Let_def by auto 
qed

lemma virt_to_phys_unchanged: 
assumes a1: "(va. virt_to_phys va (mmu s2) (mem s1) = virt_to_phys va (mmu s2) (mem s2))"
shows "(va. virt_to_phys va (mmu s2) ((mem s1)(10 := mem s1 10(addr  val), 
                                         11 := (mem s1 11)(addr := None))) =
             virt_to_phys va (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
                                         11 := (mem s2 11)(addr := None))))"
proof (cases "registers (mmu s2) CR AND 1  0")
  case True
  then have f1: "registers (mmu s2) CR AND 1  0" by auto
  then show ?thesis 
  proof (cases "mmu_reg_val (mmu s2) 256 = None")
    case True
    then show ?thesis 
    by (simp add: virt_to_phys_def)
  next
    case False
    then have f2: "mmu_reg_val (mmu s2) 256  None" by auto
    then show ?thesis 
    proof (cases "mmu_reg_val (mmu s2) 512 = None")
      case True
      then show ?thesis using f1 f2
      apply (simp add: virt_to_phys_def)
      by auto
    next
      case False
      then show ?thesis using f1 f2 a1
      apply (simp add: virt_to_phys_def)
      apply clarify
      using virt_to_phys_unchanged_sub1 by fastforce
    qed
  qed
next
  case False
  then show ?thesis 
  by (simp add: virt_to_phys_def)
qed

lemma virt_to_phys_unchanged2_sub1: 
"(case mem_context_val_w32 (word_of_int 9) 
  (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) (mem s2) of
  None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table (mem s2) 1) =
(case mem_context_val_w32 (word_of_int 9) 
  (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2)
    (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) of
  None  None | Some lvl1_page_table  ptd_lookup va lvl1_page_table ((mem s2)
    (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) 1)"
proof (cases "mem_context_val_w32 9 (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) (mem s2) = None")
  case True
  then have "mem_context_val_w32 9 (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) (mem s2) = None 
    mem_context_val_w32 9 (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2)
    (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) = None"
    using mem_context_val_w32_9_unchanged by metis
  then show ?thesis 
  by auto
next
  case False
  then have "mem_context_val_w32 9 (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) (mem s2)  None  
    (y. mem_context_val_w32 9 (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) (mem s2) = Some y 
         mem_context_val_w32 9 (ucast ((v1 >> 11 << 11) OR (v2 AND 511 << 2))) ((mem s2)
         (10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))) = Some y)"
    using mem_context_val_w32_9_unchanged by metis 
  then show ?thesis
  using ptd_lookup_unchanged_1 by fastforce 
qed

lemma virt_to_phys_unchanged2: 
"virt_to_phys va (mmu s2) (mem s2) =
virt_to_phys va (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
                                         11 := (mem s2 11)(addr := None)))"
proof (cases "registers (mmu s2) CR AND 1  0")
  case True
  then have f1: "registers (mmu s2) CR AND 1  0" by auto
  then show ?thesis 
  proof (cases "mmu_reg_val (mmu s2) 256 = None")
    case True
    then show ?thesis 
    by (simp add: virt_to_phys_def)
  next
    case False
    then have f2: "mmu_reg_val (mmu s2) 256  None" by auto
    then show ?thesis 
    proof (cases "mmu_reg_val (mmu s2) 512 = None")
      case True
      then show ?thesis using f1 f2
      apply (simp add: virt_to_phys_def)
      by auto
    next
      case False
      then show ?thesis 
      using f1 f2
      apply (simp add: virt_to_phys_def)
      apply clarify
      unfolding Let_def
      using virt_to_phys_unchanged2_sub1
      by auto      
    qed
  qed
next
  case False
  then show ?thesis 
  by (simp add: virt_to_phys_def)
qed

lemma virt_to_phys_unchanged_low_equal: 
assumes a1: "low_equal s1 s2"
shows "(va. virt_to_phys va (mmu s2) ((mem s1)(10 := mem s1 10(addr  val), 
                                         11 := (mem s1 11)(addr := None))) =
             virt_to_phys va (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
                                         11 := (mem s2 11)(addr := None))))"
using a1 apply (simp add: low_equal_def)
using virt_to_phys_unchanged
by metis 

lemma mmu_low_equal: "low_equal s1 s2  mmu s1 = mmu s2"
by (simp add: low_equal_def)

lemma mem_val_alt_8_unchanged0: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 8 (pa AND 68719476732) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 (pa AND 68719476732) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_unchanged1: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 8 ((pa AND 68719476732) + 1) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 ((pa AND 68719476732) + 1) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_unchanged2: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 8 ((pa AND 68719476732) + 2) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 ((pa AND 68719476732) + 2) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_unchanged3: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 8 ((pa AND 68719476732) + 3) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 ((pa AND 68719476732) + 3) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_8_unchanged: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 8 (pa AND 68719476732) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 (pa AND 68719476732) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None))) 
  mem_val_alt 8 ((pa AND 68719476732) + 1) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 ((pa AND 68719476732) + 1) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None))) 
  mem_val_alt 8 ((pa AND 68719476732) + 2) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 ((pa AND 68719476732) + 2) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None))) 
  mem_val_alt 8 ((pa AND 68719476732) + 3) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 8 ((pa AND 68719476732) + 3) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
using a1 mem_val_alt_8_unchanged0 mem_val_alt_8_unchanged1
mem_val_alt_8_unchanged2 mem_val_alt_8_unchanged3
by blast

lemma mem_val_w32_8_unchanged: 
assumes a1: "mem_equal s1 s2 a"
shows "mem_val_w32 8 a (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) =
mem_val_w32 8 a (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_w32_def)
apply (simp add: Let_def)
using mem_val_alt_8_unchanged a1 apply auto
        apply fastforce
       apply fastforce
      apply fastforce
     apply fastforce
    apply fastforce
   apply fastforce
  apply fastforce
 apply fastforce
by fastforce

lemma load_word_mem_8_unchanged: 
assumes a1: "low_equal s1 s2  
load_word_mem s1 addra 8 = load_word_mem s2 addra 8"
shows "load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
                                         11 := (mem s1 11)(addr := None))) addra 8 =
       load_word_mem (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
                                         11 := (mem s2 11)(addr := None))) addra 8"
proof (cases "virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = None")
  case True
  then have "virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = None 
             virt_to_phys addra (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
          11 := (mem s2 11)(addr := None))) = None"
    using a1 apply (auto simp add: mmu_low_equal)
    using a1 virt_to_phys_unchanged_low_equal by metis
  then show ?thesis
  by (simp add: load_word_mem_def)
next
  case False
  then have "p. virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = Some p 
             virt_to_phys addra (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
          11 := (mem s2 11)(addr := None))) = Some p"
    using a1 apply (auto simp add: mmu_low_equal)
    using a1 virt_to_phys_unchanged_low_equal by metis
  then have "p. virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = Some p 
            virt_to_phys addra (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
          11 := (mem s2 11)(addr := None))) = Some p  
            virt_to_phys addra (mmu s1) (mem s1) = Some p 
            virt_to_phys addra (mmu s2) (mem s2) = Some p"
    using virt_to_phys_unchanged2 by metis
  then show ?thesis using a1  
  apply (simp add: load_word_mem_def)
  apply auto
  apply (simp add: low_equal_def)
  apply (simp add: user_accessible_def)
  using mem_val_w32_8_unchanged a1 user_accessible_8
  by (metis snd_conv)
qed

lemma load_word_mem_select_8: 
assumes a1: "fst (case load_word_mem s1 addra 8 of None  (None, s1)
  | Some w  (Some w, add_instr_cache s1 addra w 15)) =
fst (case load_word_mem s2 addra 8 of None  (None, s2)
  | Some w  (Some w, add_instr_cache s2 addra w 15))"
shows "load_word_mem s1 addra 8 = load_word_mem s2 addra 8"
using a1
by (metis (mono_tags, lifting) fst_conv not_None_eq option.simps(4) option.simps(5))

lemma memory_read_8_unchanged: 
assumes a1: "low_equal s1 s2 
fst (memory_read 8 addra s1) = fst (memory_read 8 addra s2)"
shows "fst (memory_read 8 addra
                   (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
                                       11 := (mem s1 11)(addr := None)))) =
         fst (memory_read 8 addra
                   (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
                                       11 := (mem s2 11)(addr := None))))"
proof (cases "sys_reg s1 CCR AND 1 = 0")
  case True
  then have "sys_reg s1 CCR AND 1 = 0  sys_reg s2 CCR AND 1 = 0"
    using a1 sys_reg_low_equal by fastforce
  then show ?thesis using a1
  apply (simp add: memory_read_def)
  using load_word_mem_8_unchanged by blast
next
  case False
  then have f1: "sys_reg s1 CCR AND 1  0  sys_reg s2 CCR AND 1  0"
    using a1 sys_reg_low_equal by fastforce
  then show ?thesis using a1
  proof (cases "load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 8 = None")
    case True
    then have "load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 8 = None  
      load_word_mem (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
      11 := (mem s2 11)(addr := None))) addra 8 = None"
      using a1 f1  
      apply (simp add: memory_read_def)
      apply clarsimp
      using load_word_mem_select_8 load_word_mem_8_unchanged
      by fastforce      
    then show ?thesis
    by (simp add: memory_read_def)
  next
    case False
    then have "y. load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 8 = Some y" by auto
    then have "y. load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 8 = Some y  
                   load_word_mem (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
      11 := (mem s2 11)(addr := None))) addra 8 = Some y"
      using a1 f1
      apply (simp add: memory_read_def)
      apply clarsimp
      using load_word_mem_select_8 load_word_mem_8_unchanged by fastforce
    then show ?thesis using a1 f1
    apply (simp add: memory_read_def)
    by auto
  qed
qed

lemma mem_val_alt_mod: 
assumes a1: "addr1  addr2"
shows "mem_val_alt 10 addr1 s = 
mem_val_alt 10 addr1 (smem := (mem s)(10 := mem s 10(addr2  val), 
  11 := (mem s 11)(addr2 := None)))"
using a1 apply (simp add: mem_val_alt_def)
by (simp add: Let_def)

lemma mem_val_alt_mod2: 
"mem_val_alt 10 addr (smem := (mem s)(10 := mem s 10(addr  val), 
  11 := (mem s 11)(addr := None))) = Some val"
by (simp add: mem_val_alt_def)

lemma mem_val_alt_10_unchanged0: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 10 (pa AND 68719476732) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 (pa AND 68719476732) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_unchanged1: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 10 ((pa AND 68719476732) + 1) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 ((pa AND 68719476732) + 1) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_unchanged2: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 10 ((pa AND 68719476732) + 2) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 ((pa AND 68719476732) + 2) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_unchanged3: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 10 ((pa AND 68719476732) + 3) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 ((pa AND 68719476732) + 3) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_alt_def)
apply (simp add: Let_def)
using a1 apply (simp add: mem_equal_def)
by (metis option.distinct(1))

lemma mem_val_alt_10_unchanged: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_val_alt 10 (pa AND 68719476732) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 (pa AND 68719476732) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None))) 
  mem_val_alt 10 ((pa AND 68719476732) + 1) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 ((pa AND 68719476732) + 1) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None))) 
  mem_val_alt 10 ((pa AND 68719476732) + 2) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 ((pa AND 68719476732) + 2) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None))) 
  mem_val_alt 10 ((pa AND 68719476732) + 3) (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) = 
  mem_val_alt 10 ((pa AND 68719476732) + 3) (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
using a1 mem_val_alt_10_unchanged0 mem_val_alt_10_unchanged1
mem_val_alt_10_unchanged2 mem_val_alt_10_unchanged3
by blast

lemma mem_val_w32_10_unchanged: 
assumes a1: "mem_equal s1 s2 a"
shows "mem_val_w32 10 a (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None))) =
mem_val_w32 10 a (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))"
apply (simp add: mem_val_w32_def)
apply (simp add: Let_def)
using mem_val_alt_10_unchanged a1 apply auto
        apply fastforce
       apply fastforce
      apply fastforce
     apply fastforce
    apply fastforce
   apply fastforce
  apply fastforce
 apply fastforce
by fastforce

lemma is_accessible: "low_equal s1 s2 
virt_to_phys addra (mmu s1) (mem s1) = Some (a, b) 
virt_to_phys addra (mmu s2) (mem s2) = Some (a, b) 
mmu_readable (get_acc_flag b) 10 
mem_equal s1 s2 a"
apply (simp add: low_equal_def)
apply (simp add: user_accessible_def)
by fastforce

lemma load_word_mem_10_unchanged: 
assumes a1: "low_equal s1 s2  
load_word_mem s1 addra 10 = load_word_mem s2 addra 10"
shows "load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
                                         11 := (mem s1 11)(addr := None))) addra 10 =
       load_word_mem (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
                                         11 := (mem s2 11)(addr := None))) addra 10"
proof (cases "virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = None")
  case True
  then have "virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = None 
             virt_to_phys addra (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
          11 := (mem s2 11)(addr := None))) = None"
    using a1 apply (auto simp add: mmu_low_equal)
    using a1 virt_to_phys_unchanged_low_equal by metis
  then show ?thesis
  by (simp add: load_word_mem_def)
next
  case False
  then have "p. virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = Some p 
             virt_to_phys addra (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
          11 := (mem s2 11)(addr := None))) = Some p"
    using a1 apply (auto simp add: mmu_low_equal)
    using a1 virt_to_phys_unchanged_low_equal by metis
  then have "p. virt_to_phys addra (mmu s1) ((mem s1)(10 := mem s1 10(addr  val), 
          11 := (mem s1 11)(addr := None))) = Some p 
            virt_to_phys addra (mmu s2) ((mem s2)(10 := mem s2 10(addr  val), 
          11 := (mem s2 11)(addr := None))) = Some p  
            virt_to_phys addra (mmu s1) (mem s1) = Some p 
            virt_to_phys addra (mmu s2) (mem s2) = Some p"
    using virt_to_phys_unchanged2 by metis
  then show ?thesis using a1  
  apply (simp add: load_word_mem_def)
  apply auto
  apply (simp add: low_equal_def)
  apply (simp add: user_accessible_def)
  using mem_val_w32_10_unchanged a1 by metis
qed

lemma load_word_mem_select_10: 
assumes a1: "fst (case load_word_mem s1 addra 10 of None  (None, s1)
  | Some w  (Some w, add_data_cache s1 addra w 15)) =
fst (case load_word_mem s2 addra 10 of None  (None, s2)
  | Some w  (Some w, add_data_cache s2 addra w 15))"
shows "load_word_mem s1 addra 10 = load_word_mem s2 addra 10"
using a1
by (metis (mono_tags, lifting) fst_conv not_None_eq option.simps(4) option.simps(5))

lemma memory_read_10_unchanged: 
assumes a1: "low_equal s1 s2 
fst (memory_read 10 addra s1) = fst (memory_read 10 addra s2)"
shows "fst (memory_read 10 addra
                   (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
                                       11 := (mem s1 11)(addr := None)))) =
         fst (memory_read 10 addra
                   (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
                                       11 := (mem s2 11)(addr := None))))"
proof (cases "sys_reg s1 CCR AND 1 = 0")
  case True
  then have "sys_reg s1 CCR AND 1 = 0  sys_reg s2 CCR AND 1 = 0"
    using a1 sys_reg_low_equal by fastforce
  then show ?thesis using a1
  apply (simp add: memory_read_def)
  using load_word_mem_10_unchanged by blast
next
  case False
  then have f1: "sys_reg s1 CCR AND 1  0  sys_reg s2 CCR AND 1  0"
    using a1 sys_reg_low_equal by fastforce
  then show ?thesis using a1
  proof (cases "load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 10 = None")
    case True
    then have "load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 10 = None  
      load_word_mem (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
      11 := (mem s2 11)(addr := None))) addra 10 = None"
      using a1 f1  
      apply (simp add: memory_read_def)
      apply clarsimp
      using load_word_mem_select_10 load_word_mem_10_unchanged by fastforce
    then show ?thesis
    by (simp add: memory_read_def)
  next
    case False
    then have "y. load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 10 = Some y" by auto
    then have "y. load_word_mem (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
      11 := (mem s1 11)(addr := None))) addra 10 = Some y  
                   load_word_mem (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
      11 := (mem s2 11)(addr := None))) addra 10 = Some y"
      using a1 f1
      apply (simp add: memory_read_def)
      apply clarsimp
      using load_word_mem_select_10 load_word_mem_10_unchanged by fastforce
    then show ?thesis using a1 f1
    apply (simp add: memory_read_def)
    by auto
  qed
qed

lemma state_mem_mod_1011_low_equal_sub1: 
assumes a1: "(va. virt_to_phys va (mmu s2) (mem s1) =
            virt_to_phys va (mmu s2) (mem s2)) 
  (pa. (va b. virt_to_phys va (mmu s2) (mem s2) = Some (pa, b) 
  mmu_readable (get_acc_flag b) 10) 
  mem_equal s1 s2 pa) 
  mmu s1 = mmu s2 
  virt_to_phys va (mmu s2)
  ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) =
  Some (pa, b) 
  mmu_readable (get_acc_flag b) 10"
shows "mem_equal s1 s2 pa"
proof -
  have "virt_to_phys va (mmu s1)
  ((mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None))) =
  Some (pa, b)"
    using a1 by auto
  then have "virt_to_phys va (mmu s1) (mem s1) = Some (pa, b)"
    using virt_to_phys_unchanged2 by metis
  then have "virt_to_phys va (mmu s2) (mem s2) = Some (pa, b)"
    using a1 by auto
  then show ?thesis using a1 by auto
qed

lemma mem_equal_unchanged: 
assumes a1: "mem_equal s1 s2 pa"
shows "mem_equal (s1mem := (mem s1)(10 := mem s1 10(addr  val), 
  11 := (mem s1 11)(addr := None)))
 (s2mem := (mem s2)(10 := mem s2 10(addr  val), 
  11 := (mem s2 11)(addr := None)))
 pa"
using a1 apply (simp add: mem_equal_def)
by auto

lemma state_mem_mod_1011_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = s1mem := (mem s1)(10 := mem s1 10(addr  val), 11 := (mem s1 11)(addr := None)) 
t2 = s2mem := (mem s2)(10 := mem s2 10(addr  val), 11 := (mem s2 11)(addr := None))"
shows "low_equal t1 t2"
using a1
apply (simp add: low_equal_def)
apply (simp add: user_accessible_def)
apply auto
   apply (simp add: assms virt_to_phys_unchanged_low_equal)
  using state_mem_mod_1011_low_equal_sub1 mem_equal_unchanged
  apply metis
 apply (metis virt_to_phys_unchanged2)
using state_mem_mod_1011_low_equal_sub1 mem_equal_unchanged
by metis

lemma mem_mod_low_equal:
assumes a1: "low_equal s1 s2 
t1 = (mem_mod 10 addr val s1) 
t2 = (mem_mod 10 addr val s2)"
shows "low_equal t1 t2"
using a1
apply (simp add: mem_mod_def)
by (auto intro: state_mem_mod_1011_low_equal)

lemma mem_mod_w32_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = mem_mod_w32 10 a bm data s1 
t2 = mem_mod_w32 10 a bm data s2"
shows "low_equal t1 t2"
using a1
apply (simp add: mem_mod_w32_def)
apply (simp add: Let_def)
by (meson mem_mod_low_equal)

lemma store_word_mem_low_equal: 
assumes a1: "low_equal s1 s2 
Some t1 = store_word_mem s1 addr data bm 10 
Some t2 = store_word_mem s2 addr data bm 10" 
shows "low_equal t1 t2" using a1
apply (simp add: store_word_mem_def)
apply (auto simp add: virt_to_phys_low_equal)
apply (case_tac "virt_to_phys addr (mmu s2) (mem s2) = None")
 apply auto
apply (case_tac "mmu_writable (get_acc_flag b) 10")
 apply auto
using mem_mod_w32_low_equal by blast

lemma memory_write_asi_low_equal: 
assumes a1: "low_equal s1 s2 
Some t1 = memory_write_asi 10 addr bm data s1 
Some t2 = memory_write_asi 10 addr bm data s2"
shows "low_equal t1 t2"
using a1 apply (simp add: memory_write_asi_def)
by (meson add_data_cache_low_equal store_word_mem_low_equal)

lemma store_barrier_pending_mod_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = store_barrier_pending_mod False s1 
t2 = store_barrier_pending_mod False s2"
shows "low_equal t1 t2"
using a1 apply (simp add: store_barrier_pending_mod_def)
apply clarsimp
using a1 apply (auto simp add: state_var_low_equal)
by (auto intro: state_var2_low_equal)

lemma memory_write_low_equal: 
assumes a1: "low_equal s1 s2 
Some t1 = memory_write 10 addr bm data s1 
Some t2 = memory_write 10 addr bm data s2"
shows "low_equal t1 t2"
apply (case_tac "memory_write_asi 10 addr bm data s1 = None")
 using a1 apply (simp add: memory_write_def)
apply (case_tac "memory_write_asi 10 addr bm data s2 = None")
 apply (meson assms low_equal_com memory_write_asi_low_equal_none)
using a1 apply (simp add: memory_write_def)
apply auto
by (metis memory_write_asi_low_equal store_barrier_pending_mod_low_equal)

lemma memory_write_low_equal2: 
assumes a1: "low_equal s1 s2 
Some t1 = memory_write 10 addr bm data s1"
shows "t2. Some t2 = memory_write 10 addr bm data s2"
using a1
apply (simp add: memory_write_def)
apply auto
by (metis (full_types) memory_write_def memory_write_low_equal_none2 not_None_eq) 

lemma store_sub2_low_equal_sub1:
assumes a1: "low_equal s1 s2 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s1 = Some y 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s2 = Some ya"
shows "low_equal (ytraps := insert data_access_exception (traps y))
        (yatraps := insert data_access_exception (traps ya))"
proof -
  from a1 have f1: "low_equal y ya" using memory_write_low_equal by metis
  then have "traps y = traps ya" by (simp add: low_equal_def)
  then show ?thesis using f1 mod_trap_low_equal by fastforce
qed

lemma store_sub2_low_equal_sub2:
assumes a1: "low_equal s1 s2 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s1 = Some y 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s2 = Some ya 
memory_write 10 (addr + 4) 15 (user_reg_val curr_win (rd OR 1) y) y = None 
memory_write 10 (addr + 4) 15 (user_reg_val curr_win (rd OR 1) ya) ya = Some yb"
shows "False"
proof -
  from a1 have f1: "low_equal y ya" using memory_write_low_equal by metis
  then have "(user_reg_val curr_win (rd OR 1) y) = 
    (user_reg_val curr_win (rd OR 1) ya)" 
    by (simp add: low_equal_def user_reg_val_def)
  then show ?thesis using a1
  using f1 memory_write_low_equal_none by fastforce  
qed

lemma store_sub2_low_equal_sub3:
assumes a1: "low_equal s1 s2 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s1 = Some y 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s2 = Some ya 
memory_write 10 (addr + 4) 15 (user_reg_val curr_win (rd OR 1) y) y = Some yb 
memory_write 10 (addr + 4) 15 (user_reg_val curr_win (rd OR 1) ya) ya = None"
shows "False"
proof -
  from a1 have f1: "low_equal y ya" using memory_write_low_equal by metis
  then have "(user_reg_val curr_win (rd OR 1) y) = 
    (user_reg_val curr_win (rd OR 1) ya)" 
    by (simp add: low_equal_def user_reg_val_def)
  then show ?thesis using a1
  using f1 memory_write_low_equal_none2 by fastforce  
qed

lemma store_sub2_low_equal_sub4:
assumes a1: "low_equal s1 s2 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s1 = Some y 
memory_write 10 addr (st_byte_mask instr addr)
  (st_data0 instr curr_win rd addr s2) s2 = Some ya 
memory_write 10 (addr + 4) 15 (user_reg_val curr_win (rd OR 1) y) y = Some yb 
memory_write 10 (addr + 4) 15 (user_reg_val curr_win (rd OR 1) ya) ya = Some yc" 
shows "low_equal yb yc"
proof -
  from a1 have f1: "low_equal y ya" using memory_write_low_equal by metis
  then have "(user_reg_val curr_win (rd OR 1) y) = 
    (user_reg_val curr_win (rd OR 1) ya)" 
    by (simp add: low_equal_def user_reg_val_def)
  then show ?thesis using a1 f1
  by (metis memory_write_low_equal)  
qed

lemma store_sub2_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (store_sub2 instr curr_win rd 10 addr s1)) 
t2 = snd (fst (store_sub2 instr curr_win rd 10 addr s2))"
shows "low_equal t1 t2"
proof (cases "memory_write 10 addr (st_byte_mask instr addr)
        (st_data0 instr curr_win rd addr s1) s1 = None")
  case True
  then have "memory_write 10 addr (st_byte_mask instr addr)
        (st_data0 instr curr_win rd addr s1) s1 = None 
        memory_write 10 addr (st_byte_mask instr addr)
        (st_data0 instr curr_win rd addr s2) s2 = None"
    using a1 by (metis memory_write_low_equal_none st_data0_low_equal) 
  then show ?thesis using a1
  apply (simp add: store_sub2_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold return_def)
  apply (simp add: raise_trap_def add_trap_set_def)
  apply (simp add: simpler_modify_def)
  using mod_trap_low_equal traps_low_equal by fastforce  
next
  case False
  then have f1: "memory_write 10 addr (st_byte_mask instr addr) 
    (st_data0 instr curr_win rd addr s1) s1  None 
    memory_write 10 addr (st_byte_mask instr addr) 
    (st_data0 instr curr_win rd addr s2) s2  None"
    using a1 by (metis memory_write_low_equal_none2 st_data0_low_equal)     
  then show ?thesis 
  proof (cases "(fst instr)  {load_store_type STD,load_store_type STDA}")
    case True
    then show ?thesis using a1 f1
    apply (simp add: store_sub2_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
    apply (simp add: return_def)
    apply (simp add: bind_def case_prod_unfold)
    apply (simp add: simpler_modify_def)
    apply clarsimp
    apply (simp add: case_prod_unfold bind_def h1_def h2_def Let_def simpler_modify_def)
    apply (simp add: simpler_gets_def)
    apply auto
           apply (simp add: raise_trap_def add_trap_set_def)
           apply (simp add: simpler_modify_def)
           apply (simp add: st_data0_low_equal)    
           apply (simp add: store_sub2_low_equal_sub1)
          apply (simp add: st_data0_low_equal)
          using store_sub2_low_equal_sub2 apply blast
         apply (simp add: st_data0_low_equal)
         using store_sub2_low_equal_sub3 apply blast
        apply (simp add: st_data0_low_equal)
        using store_sub2_low_equal_sub4 apply blast
       apply (simp add: st_data0_low_equal)
       apply (simp add: raise_trap_def add_trap_set_def)
       apply (simp add: simpler_modify_def)
       using store_sub2_low_equal_sub1 apply blast
      apply (simp add: st_data0_low_equal)
      using store_sub2_low_equal_sub2 apply blast
     apply (simp add: st_data0_low_equal)
     using store_sub2_low_equal_sub3 apply blast
    apply (simp add: st_data0_low_equal)
    using store_sub2_low_equal_sub4 by blast
  next
    case False
    then show ?thesis using a1 f1
    apply (simp add: store_sub2_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def)
    apply (simp add: simpler_modify_def bind_def h1_def h2_def Let_def)
    apply (simp add: return_def)
    apply (simp add: bind_def case_prod_unfold)
    apply clarsimp
    apply (simp add: simpler_modify_def)
    apply (simp add: st_data0_low_equal)
    using memory_write_low_equal by metis
  qed
qed

lemma store_sub1_low_equal:
assumes a1: "low_equal s1 s2 
(fst instr = load_store_type STB 
fst instr = load_store_type STH 
fst instr = load_store_type ST  
fst instr = load_store_type STD) 
t1 = snd (fst (store_sub1 instr rd 0 s1)) 
t2 = snd (fst (store_sub1 instr rd 0 s2))"
shows "low_equal t1 t2"
proof (cases "(fst instr = load_store_type STH  fst instr = load_store_type STHA) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word1)  0")
  case True
  then have "((fst instr = load_store_type STH  fst instr = load_store_type STHA) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word1)  0)  
             ((fst instr = load_store_type STH  fst instr = load_store_type STHA) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word1)  0)"
    by (metis (mono_tags, lifting) assms get_addr_low_equal) 
  then show ?thesis using a1
  apply (simp add: store_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply (simp add: raise_trap_def add_trap_set_def)
  apply (simp add: simpler_modify_def)
  apply clarsimp
  apply (simp add: get_curr_win3_low_equal)
  by (auto intro: get_curr_win2_low_equal mod_trap_low_equal)
next
  case False
  then have f1: "¬ ((fst instr = load_store_type STH  fst instr = load_store_type STHA) 
      ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word1)  0) 
      ¬ ((fst instr = load_store_type STH  fst instr = load_store_type STHA) 
      ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word1)  0)"
    by (metis (mono_tags, lifting) assms get_addr_low_equal) 
  then show ?thesis 
  proof (cases "(fst instr  {load_store_type ST,load_store_type STA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2)  0")
    case True
    then have "(fst instr  {load_store_type ST,load_store_type STA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2)  0 
              (fst instr  {load_store_type ST,load_store_type STA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word2)  0"
      by (metis (mono_tags, lifting) assms get_addr_low_equal) 
    then show ?thesis using a1 f1
    apply (simp add: store_sub1_def)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
    apply (simp add: case_prod_unfold) 
    apply (simp add: raise_trap_def add_trap_set_def)
    apply (simp add: simpler_modify_def)
    apply clarsimp
    apply (simp add: get_curr_win3_low_equal)
    by (auto intro: get_curr_win2_low_equal mod_trap_low_equal)
  next
    case False
    then have "¬((fst instr  {load_store_type ST,load_store_type STA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2)  0) 
              ¬((fst instr  {load_store_type ST,load_store_type STA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word2)  0)"
      by (metis (mono_tags, lifting) assms get_addr_low_equal) 
    then have f2: "¬((fst instr = load_store_type ST  fst instr = load_store_type STA) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word2)  0) 
              ¬((fst instr = load_store_type ST  fst instr = load_store_type STA) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word2)  0)"
      by auto
    then show ?thesis 
    proof (cases "(fst instr  {load_store_type STD,load_store_type STDA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3)  0")
      case True
      then have "(fst instr  {load_store_type STD,load_store_type STDA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3)  0 
              (fst instr  {load_store_type STD,load_store_type STDA}) 
              ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word3)  0"
        by (metis (mono_tags, lifting) assms get_addr_low_equal) 
      then show ?thesis using a1 
      apply (simp add: store_sub1_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply auto
      apply (simp add: case_prod_unfold) 
      apply (simp add: raise_trap_def add_trap_set_def)
      apply (simp add: simpler_modify_def)
      apply (simp add: get_curr_win3_low_equal)
      by (auto intro: get_curr_win2_low_equal mod_trap_low_equal)         
    next
      case False
      then have "¬ (fst instr  {load_store_type STD, load_store_type STDA} 
        ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3)  0) 
        ¬ (fst instr  {load_store_type STD, load_store_type STDA} 
        ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word3)  0)"
        by (metis (mono_tags, lifting) assms get_addr_low_equal)
      then have f3: "¬ ((fst instr = load_store_type STD  fst instr = load_store_type STDA) 
        ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s1)))))::word3)  0) 
        ¬ ((fst instr = load_store_type STD  fst instr = load_store_type STDA) 
        ((ucast (get_addr (snd instr) (snd (fst (get_curr_win () s2)))))::word3)  0)"
        by auto
      show ?thesis using a1
      apply (simp add: store_sub1_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (unfold case_prod_beta)
      apply (simp add: f1 f2 f3)
      apply (simp_all add: st_asi_def)
      using a1 apply clarsimp
      apply (simp add: get_curr_win_low_equal get_addr2_low_equal)
      by (metis store_sub2_low_equal get_curr_win2_low_equal)      
    qed
  qed
qed

lemma store_instr_low_equal: 
assumes a1: "low_equal s1 s2 
(fst instr = load_store_type STB 
fst instr = load_store_type STH 
fst instr = load_store_type ST  
fst instr = load_store_type STA  
fst instr = load_store_type STD) 
(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
t1 = snd (fst (store_instr instr s1))  t2 = snd (fst (store_instr instr s2))"
shows "low_equal t1 t2"
proof -
  have "get_S (cpu_reg_val PSR s1) = 0  get_S (cpu_reg_val PSR s2) = 0"
    using a1 by (simp add: ucast_id) 
  then show ?thesis using a1
  apply (simp add: store_instr_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: Let_def)
  apply clarsimp
  apply (simp add: raise_trap_def add_trap_set_def)
  apply (simp add: simpler_modify_def)
  apply (simp add: traps_low_equal)
  by (auto intro: mod_trap_low_equal store_sub1_low_equal)
qed

lemma sethi_low_equal: "low_equal s1 s2 
t1 = snd (fst (sethi_instr instr s1))  t2 = snd (fst (sethi_instr instr s2)) 
low_equal t1 t2"
apply (simp add: sethi_instr_def)
apply (simp add: Let_def)
apply (case_tac "get_operand_w5 (snd instr ! Suc 0)  0")
 apply auto
 apply (simp add: bind_def h1_def h2_def Let_def)
 apply (simp add: case_prod_unfold)
 apply (simp add: get_curr_win_low_equal)
 using get_curr_win2_low_equal write_reg_low_equal
 apply metis
by (simp add: return_def)

lemma nop_low_equal: "low_equal s1 s2 
t1 = snd (fst (nop_instr instr s1))  t2 = snd (fst (nop_instr instr s2)) 
low_equal t1 t2"
apply (simp add: nop_instr_def)
by (simp add: return_def)

lemma logical_instr_sub1_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (logical_instr_sub1 instr_name result s1))  
t2 = snd (fst (logical_instr_sub1 instr_name result s2))"
shows "low_equal t1 t2"
proof (cases "instr_name = logic_type ANDcc 
              instr_name = logic_type ANDNcc 
              instr_name = logic_type ORcc 
              instr_name = logic_type ORNcc 
              instr_name = logic_type XORcc  instr_name = logic_type XNORcc")
  case True
  then show ?thesis using a1
  apply (simp add: logical_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: logical_new_psr_val_def)    
  using write_cpu_low_equal cpu_reg_val_low_equal
  by fastforce  
next
  case False
  then show ?thesis using a1
  apply (simp add: logical_instr_sub1_def)
  by (simp add: return_def)
qed

lemma logical_instr_low_equal: "low_equal s1 s2 
t1 = snd (fst (logical_instr instr s1))  t2 = snd (fst (logical_instr instr s2)) 
low_equal t1 t2"
apply (simp add: logical_instr_def)
apply (simp add: Let_def simpler_gets_def bind_def h1_def h2_def)
apply (simp add: case_prod_unfold)
apply auto
 apply (simp_all add: get_curr_win_low_equal)
 apply (simp_all add: get_operand2_low_equal)
 using logical_instr_sub1_low_equal get_operand2_low_equal
 get_curr_win2_low_equal write_reg_low_equal user_reg_val_low_equal
 proof -
  assume a1: "low_equal s1 s2"
  assume "t2 = snd (fst (logical_instr_sub1 (fst instr) (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2)) (snd (fst (write_reg (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))))"
  assume "t1 = snd (fst (logical_instr_sub1 (fst instr) (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s2)) (snd (fst (write_reg (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s2)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))"
  have "w wa. user_reg_val w wa (snd (fst (get_curr_win () s2))) = user_reg_val w wa (snd (fst (get_curr_win () s1)))"
    using a1 by (metis (no_types) get_curr_win2_low_equal user_reg_val_low_equal)
  then show "low_equal (snd (fst (logical_instr_sub1 (fst instr) (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s2)) (snd (fst (write_reg (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s2)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))) (snd (fst (logical_instr_sub1 (fst instr) (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2)) (snd (fst (write_reg (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))))))"
    using a1 by (metis (no_types) get_curr_win2_low_equal logical_instr_sub1_low_equal write_reg_low_equal)
 next
  assume a2: "low_equal s1 s2"
  assume "t1 = snd (fst (logical_instr_sub1 (fst instr)
                    (logical_result (fst instr)
                      (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                        (snd (fst (get_curr_win () s1))))
                      (get_operand2 (snd instr) s2))
                    (snd (fst (write_reg
                                (user_reg_val (fst (fst (get_curr_win () s2))) 0
                                  (snd (fst (get_curr_win () s1))))
                                (fst (fst (get_curr_win () s2))) 0
                                (snd (fst (get_curr_win () s1))))))))"
  assume "t2 = snd (fst (logical_instr_sub1 (fst instr)
                    (logical_result (fst instr)
                      (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                        (snd (fst (get_curr_win () s2))))
                      (get_operand2 (snd instr) s2))
                    (snd (fst (write_reg
                                (user_reg_val (fst (fst (get_curr_win () s2))) 0
                                  (snd (fst (get_curr_win () s2))))
                                (fst (fst (get_curr_win () s2))) 0
                                (snd (fst (get_curr_win () s2))))))))"
  have "w wa. user_reg_val w wa (snd (fst (get_curr_win () s2))) = user_reg_val w wa (snd (fst (get_curr_win () s1)))"
    using a2 by (metis (no_types) get_curr_win2_low_equal user_reg_val_low_equal)
  then show "low_equal
     (snd (fst (logical_instr_sub1 (fst instr)
                 (logical_result (fst instr)
                   (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                     (snd (fst (get_curr_win () s1))))
                   (get_operand2 (snd instr) s2))
                 (snd (fst (write_reg
                             (user_reg_val (fst (fst (get_curr_win () s2))) 0
                               (snd (fst (get_curr_win () s1))))
                             (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1)))))))))
     (snd (fst (logical_instr_sub1 (fst instr)
                 (logical_result (fst instr)
                   (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                     (snd (fst (get_curr_win () s2))))
                   (get_operand2 (snd instr) s2))
                 (snd (fst (write_reg
                             (user_reg_val (fst (fst (get_curr_win () s2))) 0
                               (snd (fst (get_curr_win () s2))))
                             (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))))))))"
  proof -
    have "low_equal (snd (fst (logical_instr_sub1 (fst instr) (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s2)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (logical_instr_sub1 (fst instr) (logical_result (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s2)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))))))))"
      by (meson a2 get_curr_win2_low_equal logical_instr_sub1_low_equal write_reg_low_equal)
    then show ?thesis
      using wa w. user_reg_val w wa (snd (fst (get_curr_win () s2))) = user_reg_val w wa (snd (fst (get_curr_win () s1))) by presburger
  qed   
 qed

lemma shift_instr_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (shift_instr instr s1))  t2 = snd (fst (shift_instr instr s2))"
shows "low_equal t1 t2"
proof (cases "(fst instr = shift_type SLL)  (get_operand_w5 ((snd instr)!3)  0)")
  case True
  then show ?thesis using a1
  apply (simp add: shift_instr_def)
  apply (simp add: Let_def)
  apply (simp add: simpler_gets_def)
  apply (simp add: bind_def h1_def h2_def Let_def case_prod_unfold)
  apply auto
    apply (simp_all add: get_curr_win_low_equal)
    proof -
      assume a1: "low_equal s1 s2"
      assume "t2 = snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) << unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s2))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))"
      assume "t1 = snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) << unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s1))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))"
      have "w wa wb. low_equal (snd (fst (write_reg w wa wb s1))) (snd (fst (write_reg w wa wb s2)))"
        using a1 by (metis write_reg_low_equal)
      then show "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) << unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s1))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) << unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s2))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))"
        using a1 by (simp add: get_curr_win_def simpler_gets_def user_reg_val_low_equal)
    next
      assume a2: "low_equal s1 s2"
      assume "t1 = snd (fst (write_reg
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s1))) <<
                     unat (get_operand_w5 (snd instr ! 2)))
                    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                    (snd (fst (get_curr_win () s1)))))"
      assume "t2 = snd (fst (write_reg
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s2))) <<
                     unat (get_operand_w5 (snd instr ! 2)))
                    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                    (snd (fst (get_curr_win () s2)))))"
      have "w wa wb. low_equal (snd (fst (write_reg w wa wb s1))) (snd (fst (write_reg w wa wb s2)))"
        using a2 by (metis write_reg_low_equal)
      then show "low_equal
                (snd (fst (write_reg
                 (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s1))) <<
                  unat (get_operand_w5 (snd instr ! 2)))
                 (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                 (snd (fst (get_curr_win () s1))))))
                (snd (fst (write_reg
                 (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s2))) <<
                  unat (get_operand_w5 (snd instr ! 2)))
                 (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                 (snd (fst (get_curr_win () s2))))))"
      proof -
        assume a1: "w wa wb. low_equal (snd (fst (write_reg w wa wb s1))) (snd (fst (write_reg w wa wb s2)))"
        have "u s. fst (get_curr_win u s) = (ucast (get_CWP (cpu_reg_val PSR s))::'a word, s)"
          by (simp add: get_curr_win_def simpler_gets_def)
        then show ?thesis
          using a1 assms user_reg_val_low_equal by fastforce
      qed      
    qed
next
  case False
  then have f1: "¬((fst instr = shift_type SLL)  (get_operand_w5 ((snd instr)!3)  0))"
    by auto
  then show ?thesis
  proof (cases "(fst instr = shift_type SRL)  (get_operand_w5 ((snd instr)!3)  0)")
    case True
    then show ?thesis using a1 f1
    apply (simp add: shift_instr_def)
    apply (simp add: Let_def)
    apply (simp add: simpler_gets_def)
    apply (simp add: bind_def h1_def h2_def Let_def case_prod_unfold)
    apply auto
      apply (simp_all add: get_curr_win_low_equal)
      proof -
        assume a1: "low_equal s1 s2"
        assume "t2 = snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) >> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s2))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))"
        assume "t1 = snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) >> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s1))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))"
        have "u s. fst (get_curr_win u s) = (ucast (get_CWP (cpu_reg_val PSR s))::'a word, s)"
          by (simp add: get_curr_win_def simpler_gets_def)
        then show "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) >> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s1))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) >> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s2))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))"
          using a1 user_reg_val_low_equal write_reg_low_equal by fastforce
      next
        assume a2: "low_equal s1 s2"
        assume "t1 = snd (fst (write_reg
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s1))) >>
                     unat (get_operand_w5 (snd instr ! 2)))
                    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                    (snd (fst (get_curr_win () s1)))))" 
        assume "t2 = snd (fst (write_reg
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s2))) >>
                     unat (get_operand_w5 (snd instr ! 2)))
                    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                    (snd (fst (get_curr_win () s2)))))"
        have "u s. fst (get_curr_win u s) = (ucast (get_CWP (cpu_reg_val PSR s))::'a word, s)"
          by (simp add: get_curr_win_def simpler_gets_def)
        then show "low_equal
                (snd (fst (write_reg
                 (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s1))) >>
                  unat (get_operand_w5 (snd instr ! 2)))
                 (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                 (snd (fst (get_curr_win () s1))))))
                (snd (fst (write_reg
                 (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s2))) >>
                  unat (get_operand_w5 (snd instr ! 2)))
                 (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                 (snd (fst (get_curr_win () s2))))))"
          using a2 user_reg_val_low_equal write_reg_low_equal by fastforce
      qed  
  next
    case False
    then have f2: "¬((fst instr = shift_type SRL)  (get_operand_w5 ((snd instr)!3)  0))"
      by auto
    then show ?thesis 
    proof (cases "(fst instr = shift_type SRA)  (get_operand_w5 ((snd instr)!3)  0)")
      case True
      then show ?thesis using a1 f1 f2
      apply (simp add: shift_instr_def)
      apply (simp add: Let_def)
      apply (simp add: simpler_gets_def)
      apply (simp add: bind_def h1_def h2_def Let_def case_prod_unfold)
      apply auto
       apply (simp_all add: get_curr_win_low_equal)
       proof -
        assume a1: "low_equal s1 s2"
        assume "t1 = snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) >>> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s1))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))"
        assume "t2 = snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) >>> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s2))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))"
        have "w wa. user_reg_val wa w (snd (fst (get_curr_win () s1))) = user_reg_val wa w (snd (fst (get_curr_win () s2)))"
          using a1 by (meson get_curr_win2_low_equal user_reg_val_low_equal)
        then show "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) >>> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s1))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) >>> unat (ucast (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 2)) (snd (fst (get_curr_win () s2))))::word5)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))"
          using a1 by (metis (no_types) get_curr_win2_low_equal write_reg_low_equal)
       next
        assume a2: "low_equal s1 s2"
        assume "t1 = snd (fst (write_reg
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s1))) >>>
                     unat (get_operand_w5 (snd instr ! 2)))
                    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                    (snd (fst (get_curr_win () s1)))))"
        assume "t2 = snd (fst (write_reg
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s2))) >>>
                     unat (get_operand_w5 (snd instr ! 2)))
                    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                    (snd (fst (get_curr_win () s2)))))"
        have "w wa. user_reg_val wa w (snd (fst (get_curr_win () s1))) = user_reg_val wa w (snd (fst (get_curr_win () s2)))"
          using a2 by (meson get_curr_win2_low_equal user_reg_val_low_equal)
        then show "low_equal
                (snd (fst (write_reg
                 (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s1))) >>>
                  unat (get_operand_w5 (snd instr ! 2)))
                 (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                 (snd (fst (get_curr_win () s1))))))
                (snd (fst (write_reg
                 (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s2))) >>>
                  unat (get_operand_w5 (snd instr ! 2)))
                 (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                 (snd (fst (get_curr_win () s2))))))"
           using a2 get_curr_win2_low_equal write_reg_low_equal by fastforce         
       qed
    next
      case False
      then show ?thesis using a1 f1 f2
      apply (simp add: shift_instr_def)
      apply (simp add: Let_def) 
      apply (simp add: simpler_gets_def)
      apply (simp add: bind_def h1_def h2_def Let_def case_prod_unfold)
      apply (simp add: return_def)
      using get_curr_win2_low_equal by blast
    qed
  qed
qed

lemma add_instr_sub1_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (add_instr_sub1 instr_name result rs1_val operand2 s1)) 
t2 = snd (fst (add_instr_sub1 instr_name result rs1_val operand2 s2))"
shows "low_equal t1 t2"
proof (cases "instr_name = arith_type ADDcc  instr_name = arith_type ADDXcc")
  case True
  then show ?thesis using a1
  apply (simp add: add_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (clarsimp simp add: cpu_reg_val_low_equal)
  using write_cpu_low_equal by blast
next
  case False
  then show ?thesis using a1
  apply (simp add: add_instr_sub1_def)
  by (simp add: return_def)
qed

lemma add_instr_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (add_instr instr s1))  t2 = snd (fst (add_instr instr s2))"
shows "low_equal t1 t2"
proof -
  have f1: "low_equal s1 s2 
        t1 = snd (fst (add_instr_sub1 (fst instr)
                    (if fst instr = arith_type ADD  fst instr = arith_type ADDcc
                     then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s1))) +
                          get_operand2 (snd instr) s1
                     else user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s1))) +
                          get_operand2 (snd instr) s1 +
                          ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1))))))
                    (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s1))))
                    (get_operand2 (snd instr) s1)
                    (snd (fst (write_reg
                                (if get_operand_w5 (snd instr ! 3)  0
                                 then if fst instr = arith_type ADD  fst instr = arith_type ADDcc
                                      then user_reg_val (fst (fst (get_curr_win () s1)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s1))) +
                                           get_operand2 (snd instr) s1
                                      else user_reg_val (fst (fst (get_curr_win () s1)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s1))) +
                                           get_operand2 (snd instr) s1 +
                                           ucast (get_icc_C
                                                   (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))
                                 else user_reg_val (fst (fst (get_curr_win () s1)))
                                       (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))
                                (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3))
                                (snd (fst (get_curr_win () s1)))))))) 
    t2 = snd (fst (add_instr_sub1 (fst instr)
                    (if fst instr = arith_type ADD  fst instr = arith_type ADDcc
                     then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s2))) +
                          get_operand2 (snd instr) s2
                     else user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s2))) +
                          get_operand2 (snd instr) s2 +
                          ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2))))))
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s2))))
                    (get_operand2 (snd instr) s2)
                    (snd (fst (write_reg
                                (if get_operand_w5 (snd instr ! 3)  0
                                 then if fst instr = arith_type ADD  fst instr = arith_type ADDcc
                                      then user_reg_val (fst (fst (get_curr_win () s2)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s2))) +
                                           get_operand2 (snd instr) s2
                                      else user_reg_val (fst (fst (get_curr_win () s2)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s2))) +
                                           get_operand2 (snd instr) s2 +
                                           ucast (get_icc_C
                                                   (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))
                                 else user_reg_val (fst (fst (get_curr_win () s2)))
                                       (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))
                                (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                                (snd (fst (get_curr_win () s2))))))))"
  using a1 apply (simp add: add_instr_def)
  apply (simp add: Let_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (simp add: case_prod_unfold)
  then show ?thesis
  proof (cases "get_operand_w5 (snd instr ! 3)  0")
    case True
    then have f2: "get_operand_w5 (snd instr ! 3)  0" by auto
    then show ?thesis
    proof (cases "fst instr = arith_type ADD  fst instr = arith_type ADDcc")
      case True
      then show ?thesis 
      using f1 f2 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        assume "t1 = snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))"
        assume a2: "t2 = snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))))"
        have f3: "is. get_operand2 is s1 = get_operand2 is s2"
          using a1 by (metis get_operand2_low_equal)
        have f4: "fst (fst (get_curr_win () s1)) = fst (fst (get_curr_win () s2))"
          using a1 by (meson get_curr_win_low_equal)
        have "s. snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) s + get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) s) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) s + get_operand2 (snd instr) s2) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))))) = t2  ¬ low_equal s (snd (fst (get_curr_win () s2)))"
          using a2 user_reg_val_low_equal by fastforce
        then show "low_equal (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))) (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))))))"
          using f4 f3 a2 a1 by (metis (no_types) add_instr_sub1_low_equal get_curr_win2_low_equal write_reg_low_equal)
      qed
    next
      case False
      then show ?thesis
      using f1 f2 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        have f2: "s sa sb w wa wb sc. (¬ low_equal s sa  sb  snd (fst (write_reg w (wa::'a word) wb s))  sc  snd (fst (write_reg w wa wb sa)))  low_equal sb sc"
          by (meson write_reg_low_equal)
        have f3: "gets (λs. ucast (get_CWP (cpu_reg_val PSR s))::'a word) = get_curr_win ()"
          by (simp add: get_curr_win_def)
        then have "((ucast (get_CWP (cpu_reg_val PSR s1)), s1), False) = (fst (get_curr_win () s1), snd (get_curr_win () s1))"
          by (metis (no_types) prod.collapse simpler_gets_def)
        then have "(ucast (get_CWP (cpu_reg_val PSR s1)), s1) = fst (get_curr_win () s1)  ¬ snd (get_curr_win () s1)"
          by blast
        then have f4: "ucast (get_CWP (cpu_reg_val PSR s1)) = fst (fst (get_curr_win () s1))  s1 = snd (fst (get_curr_win () s1))"
          by (metis (no_types) prod.collapse prod.simps(1))
        have "((ucast (get_CWP (cpu_reg_val PSR s2)), s2), False) = (fst (get_curr_win () s2), snd (get_curr_win () s2))"
          using f3 by (metis (no_types) prod.collapse simpler_gets_def)
        then have "(ucast (get_CWP (cpu_reg_val PSR s2)), s2) = fst (get_curr_win () s2)  ¬ snd (get_curr_win () s2)"
          by blast
        then have f5: "ucast (get_CWP (cpu_reg_val PSR s2)) = fst (fst (get_curr_win () s2))  s2 = snd (fst (get_curr_win () s2))"
          by (metis prod.collapse prod.simps(1))
        then have f6: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2))) = low_equal s1 s2"
          using f4 by presburger
        have f7: "fst (fst (get_curr_win () s1)) = ucast (get_CWP (cpu_reg_val PSR s1))"
          using f4 by presburger
        have f8: "cpu_reg_val PSR s1 = cpu_reg_val PSR s2"
          using a1 by (meson cpu_reg_val_low_equal)
        have f9: "user_reg_val (ucast (get_CWP (cpu_reg_val PSR s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) = user_reg_val (ucast (get_CWP (cpu_reg_val PSR s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))"
          using f6 a1 by (meson user_reg_val_low_equal)
        have f10: "ucast (get_CWP (cpu_reg_val PSR s2)) = fst (fst (get_curr_win () s2))"
          using f5 by meson
        have f11: "s sa is. ¬ low_equal (s::'a sparc_state) sa  get_operand2 is s = get_operand2 is sa"
          using get_operand2_low_equal by blast
        then have f12: "user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1))))) = user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))"
          using f9 f8 f5 f4 a1 by auto
        then have "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))"
          using f10 f8 f6 f4 f2 a1 by simp
        then show "low_equal (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))) (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))))))"
          using f12 f11 f10 f9 f8 f7 a1 add_instr_sub1_low_equal by fastforce
      qed      
    qed
  next
    case False
    then have f3: "¬ get_operand_w5 (snd instr ! 3)  0" by auto
    then show ?thesis
    proof (cases "fst instr = arith_type ADD  fst instr = arith_type ADDcc")
      case True
      then show ?thesis
      using f1 f3 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        assume "t1 = snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))))))))"
        assume "t2 = snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))))"
        have f2: "is. get_operand2 is s1 = get_operand2 is s2"
          using a1 by (meson get_operand2_low_equal)
        have f3: "fst (fst (get_curr_win () s1)) = fst (fst (get_curr_win () s2))"
          using a1 by (meson get_curr_win_low_equal)
        have "w wa. user_reg_val wa w (snd (fst (get_curr_win () s1))) = user_reg_val wa w (snd (fst (get_curr_win () s2)))"
          using a1 by (meson get_curr_win2_low_equal user_reg_val_low_equal)
        then show "low_equal (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))))))))"
          using f3 f2 a1 by (metis (no_types) add_instr_sub1_low_equal get_curr_win2_low_equal write_reg_low_equal)
      qed      
    next
      case False
      then show ?thesis
      using f1 f3 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        have f2: "gets (λs. ucast (get_CWP (cpu_reg_val PSR s))::'a word) = get_curr_win ()"
          by (simp add: get_curr_win_def)
        then have "((ucast (get_CWP (cpu_reg_val PSR s1)), s1), False) = (fst (get_curr_win () s1), snd (get_curr_win () s1))"
          by (metis (no_types) prod.collapse simpler_gets_def)
        then have "(ucast (get_CWP (cpu_reg_val PSR s1)), s1) = fst (get_curr_win () s1)  ¬ snd (get_curr_win () s1)"
          by fastforce
        then have f3: "ucast (get_CWP (cpu_reg_val PSR s1)) = fst (fst (get_curr_win () s1))  s1 = snd (fst (get_curr_win () s1))"
          by (metis prod.collapse prod.simps(1))
        have "((ucast (get_CWP (cpu_reg_val PSR s2)), s2), False) = (fst (get_curr_win () s2), snd (get_curr_win () s2))"
          using f2 by (metis (no_types) prod.collapse simpler_gets_def)
        then have "(ucast (get_CWP (cpu_reg_val PSR s2)), s2) = fst (get_curr_win () s2)  ¬ snd (get_curr_win () s2)"
          by fastforce
        then have f4: "ucast (get_CWP (cpu_reg_val PSR s2)) = fst (fst (get_curr_win () s2))  s2 = snd (fst (get_curr_win () s2))"
          by (metis (no_types) prod.collapse prod.simps(1))
        then have f5: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2))) = low_equal s1 s2"
          using f3 by presburger
        have f6: "fst (fst (get_curr_win () s1)) = ucast (get_CWP (cpu_reg_val PSR s1))"
          using f3 by auto
        have f7: "cpu_reg_val PSR s1 = cpu_reg_val PSR s2"
          using a1 by (meson cpu_reg_val_low_equal)
        have f8: "s sa w wa. ¬ low_equal s sa  user_reg_val (w::'a word) wa s = user_reg_val w wa sa"
          by (meson user_reg_val_low_equal)
        have f9: "ucast (get_CWP (cpu_reg_val PSR s2)) = fst (fst (get_curr_win () s2))"
          using f4 by meson
        have "s sa is. ¬ low_equal (s::'a sparc_state) sa  get_operand2 is s = get_operand2 is sa"
          using get_operand2_low_equal by blast
        then have f10: "get_operand2 (snd instr) s1 = get_operand2 (snd instr) s2"
          using a1 by meson
        have f11: "cpu_reg_val PSR (snd (fst (get_curr_win () s2))) = cpu_reg_val PSR s1"
          using f4 a1 by (simp add: cpu_reg_val_low_equal)
        have f12: "user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))) = 0"
          by (meson user_reg_val_def)
        have "user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))) = 0"
          by (meson user_reg_val_def)
        then have "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))"
          using f12 f9 f7 f5 f3 a1 write_reg_low_equal by fastforce
        then have "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))  snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))))))) = snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (if get_operand_w5 (snd instr ! Suc 0) = 0 then 0 else user_reg (snd (fst (get_curr_win () s2))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))))))))  snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))))))) = snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (if get_operand_w5 (snd instr ! Suc 0) = 0 then 0 else user_reg (snd (fst (get_curr_win () s2))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))))"
          using f11 f10 f9 f8 f7 f6 f5 f3 a1 by (simp add: user_reg_val_def)
        then show "low_equal (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) + get_operand2 (snd instr) s1 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (add_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) + get_operand2 (snd instr) s2 + ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))))))))"
          using add_instr_sub1_low_equal by blast
      qed      
    qed
  qed
qed

lemma sub_instr_sub1_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (sub_instr_sub1 instr_name result rs1_val operand2 s1))  
t2 = snd (fst (sub_instr_sub1 instr_name result rs1_val operand2 s2))"
shows "low_equal t1 t2"
proof (cases "instr_name = arith_type SUBcc  instr_name = arith_type SUBXcc")
  case True
  then show ?thesis using a1
  apply (simp add: sub_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (clarsimp simp add: cpu_reg_val_low_equal)
  using write_cpu_low_equal by blast
next
  case False
  then show ?thesis using a1
  apply (simp add: sub_instr_sub1_def)
  by (simp add: return_def)
qed

lemma sub_instr_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (sub_instr instr s1))  t2 = snd (fst (sub_instr instr s2))"
shows "low_equal t1 t2"
proof -
  have f1: "low_equal s1 s2 
    t1 = snd (fst (sub_instr_sub1 (fst instr)
                    (if fst instr = arith_type SUB  fst instr = arith_type SUBcc
                     then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s1))) -
                          get_operand2 (snd instr) s1
                     else user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s1))) -
                          get_operand2 (snd instr) s1 -
                          ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1))))))
                    (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s1))))
                    (get_operand2 (snd instr) s1)
                    (snd (fst (write_reg
                                (if get_operand_w5 (snd instr ! 3)  0
                                 then if fst instr = arith_type SUB  fst instr = arith_type SUBcc
                                      then user_reg_val (fst (fst (get_curr_win () s1)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s1))) -
                                           get_operand2 (snd instr) s1
                                      else user_reg_val (fst (fst (get_curr_win () s1)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s1))) -
                                           get_operand2 (snd instr) s1 -
                                           ucast (get_icc_C
                                                   (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))
                                 else user_reg_val (fst (fst (get_curr_win () s1)))
                                       (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))
                                (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3))
                                (snd (fst (get_curr_win () s1)))))))) 
    t2 = snd (fst (sub_instr_sub1 (fst instr)
                    (if fst instr = arith_type SUB  fst instr = arith_type SUBcc
                     then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s2))) -
                          get_operand2 (snd instr) s2
                     else user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                           (snd (fst (get_curr_win () s2))) -
                          get_operand2 (snd instr) s2 -
                          ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2))))))
                    (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                      (snd (fst (get_curr_win () s2))))
                    (get_operand2 (snd instr) s2)
                    (snd (fst (write_reg
                                (if get_operand_w5 (snd instr ! 3)  0
                                 then if fst instr = arith_type SUB  fst instr = arith_type SUBcc
                                      then user_reg_val (fst (fst (get_curr_win () s2)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s2))) -
                                           get_operand2 (snd instr) s2
                                      else user_reg_val (fst (fst (get_curr_win () s2)))
                                            (get_operand_w5 (snd instr ! Suc 0))
                                            (snd (fst (get_curr_win () s2))) -
                                           get_operand2 (snd instr) s2 -
                                           ucast (get_icc_C
                                                   (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))
                                 else user_reg_val (fst (fst (get_curr_win () s2)))
                                       (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))
                                (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
                                (snd (fst (get_curr_win () s2))))))))"
  using a1 apply (simp add: sub_instr_def)
  apply (simp add: Let_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (simp add: case_prod_unfold)
  then show ?thesis
  proof (cases "get_operand_w5 (snd instr ! 3)  0")
    case True
    then have f2: "get_operand_w5 (snd instr ! 3)  0" by auto
    then show ?thesis
    proof (cases "fst instr = arith_type SUB  fst instr = arith_type SUBcc")
      case True
      then show ?thesis
      using f1 f2 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        assume a2: "t1 = snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))"
        assume a3: "t2 = snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))))"
        then have f4: "snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s1) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))))) = t2"
          using a1 by (simp add: get_operand2_low_equal)
        have "s. ¬ low_equal (snd (fst (get_curr_win () s1))) s  snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) s - get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) s) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) s - get_operand2 (snd instr) s1) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))))) = t1"
          using a2 a1 by (simp add: get_curr_win_low_equal user_reg_val_low_equal)
        then show "low_equal (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))) (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))))))"
          using f4 a3 a2 a1 by (metis (no_types) get_curr_win2_low_equal sub_instr_sub1_low_equal write_reg_low_equal)
      qed      
    next
      case False
      then show ?thesis
      using f1 f2 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        have f2: "fst (get_curr_win () s1) = (ucast (get_CWP (cpu_reg_val PSR s1)), s1)"
          by (simp add: get_curr_win_def simpler_gets_def)
        have f3: "cpu_reg_val PSR s1 = cpu_reg_val PSR s2"
          using a1 by (meson cpu_reg_val_low_equal)
        then have f4: "user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) = user_reg_val (ucast (get_CWP (cpu_reg_val PSR s2))) (get_operand_w5 (snd instr ! Suc 0)) s1"
          using f2 by simp
        have f5: "s sa is. ¬ low_equal (s::'a sparc_state) sa  get_operand2 is s = get_operand2 is sa"
          using get_operand2_low_equal by blast
        then have f6: "sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (ucast (get_CWP (cpu_reg_val PSR s2))) (get_operand_w5 (snd instr ! Suc 0)) s2) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))) = sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))"
          using f4 a1 by (simp add: user_reg_val_low_equal)
        have f7: "fst (get_curr_win () s2) = (ucast (get_CWP (cpu_reg_val PSR s2)), s2)"
          by (simp add: get_curr_win_def simpler_gets_def)
        then have f8: "user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2))))) = user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))"
          using f5 f2 a1 by (simp add: cpu_reg_val_low_equal user_reg_val_low_equal)
        then have f9: "sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (ucast (get_CWP (cpu_reg_val PSR s2))) (get_operand_w5 (snd instr ! Suc 0)) s2) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))) = sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))"
          using f7 by fastforce
        have "write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (ucast (get_CWP (cpu_reg_val PSR s2))) (get_operand_w5 (snd instr ! 3)) s2 = write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))"
          using f8 f7 by simp
        then have "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2))))))"
          using f3 f2 a1 by (metis (no_types) prod.sel(1) prod.sel(2) write_reg_low_equal)
        then show "low_equal (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s1))))))))) (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (get_curr_win () s2)))))))))"
          using f9 f6 by (metis (no_types) sub_instr_sub1_low_equal)
      qed      
    qed
  next
    case False
    then have f3: "¬ get_operand_w5 (snd instr ! 3)  0" by auto
    then show ?thesis
    proof (cases "fst instr = arith_type SUB  fst instr = arith_type SUBcc")
      case True
      then show ?thesis
      using f1 f3 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        assume "t1 = snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))))))))"
        assume "t2 = snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))))"
        have f2: "is. get_operand2 is s1 = get_operand2 is s2"
          using a1 get_operand2_low_equal by blast
        have f3: "fst (fst (get_curr_win () s1)) = fst (fst (get_curr_win () s2))"
          using a1 by (meson get_curr_win_low_equal)
        have "w wa. user_reg_val wa w (snd (fst (get_curr_win () s1))) = user_reg_val wa w (snd (fst (get_curr_win () s2)))"
          using a1 by (metis (no_types) get_curr_win2_low_equal user_reg_val_low_equal)
        then show "low_equal (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))))))))"
          using f3 f2 a1 by (metis (no_types) get_curr_win2_low_equal sub_instr_sub1_low_equal write_reg_low_equal)
      qed      
    next
      case False
      then show ?thesis
      using f1 f3 apply clarsimp
      proof -
        assume a1: "low_equal s1 s2"
        have f2: "s sa sb w wa wb sc. (¬ low_equal s sa  sb  snd (fst (write_reg w (wa::'a word) wb s))  sc  snd (fst (write_reg w wa wb sa)))  low_equal sb sc"
          by (meson write_reg_low_equal)
        have "((ucast (get_CWP (cpu_reg_val PSR s1)), s1), False) = get_curr_win () s1"
          by (simp add: get_curr_win_def simpler_gets_def)
        then have f3: "ucast (get_CWP (cpu_reg_val PSR s1)) = fst (fst (get_curr_win () s1))  s1 = snd (fst (get_curr_win () s1))"
          by (metis (no_types) prod.collapse prod.simps(1))
        have "((ucast (get_CWP (cpu_reg_val PSR s2)), s2), False) = get_curr_win () s2"
          by (simp add: get_curr_win_def simpler_gets_def)
        then have f4: "ucast (get_CWP (cpu_reg_val PSR s2)) = fst (fst (get_curr_win () s2))  s2 = snd (fst (get_curr_win () s2))"
          by (metis (no_types) prod.collapse prod.simps(1))
        have f5: "s sa sb sc w wa wb sd. (¬ low_equal (s::'a sparc_state) sa  sb  snd (fst (sub_instr_sub1 sc w wa wb s))  sd  snd (fst (sub_instr_sub1 sc w wa wb sa)))  low_equal sb sd"
          by (meson sub_instr_sub1_low_equal)
        have "low_equal (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))"
          using f4 f3 f2 a1 by (simp add: cpu_reg_val_low_equal user_reg_val_low_equal)
        then show "low_equal (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) - get_operand2 (snd instr) s1 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))))) (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) (get_operand2 (snd instr) s1) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (sub_instr_sub1 (fst instr) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) - get_operand2 (snd instr) s2 - ucast (get_icc_C (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))))) (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) (get_operand2 (snd instr) s2) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))))))))"
          using f5 f4 f3 a1 by (simp add: cpu_reg_val_low_equal get_operand2_low_equal user_reg_val_low_equal)
      qed      
    qed
  qed
qed

lemma mul_instr_sub1_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (mul_instr_sub1 instr_name result s1)) 
t2 = snd (fst (mul_instr_sub1 instr_name result s2))"
shows "low_equal t1 t2"
proof (cases "instr_name  {arith_type SMULcc,arith_type UMULcc}")
  case True
  then show ?thesis using a1
  apply (simp add: mul_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (clarsimp simp add: cpu_reg_val_low_equal)
  using write_cpu_low_equal by blast
next
  case False
  then show ?thesis using a1
  apply (simp add: mul_instr_sub1_def)
  by (simp add: return_def)
qed

lemma mul_instr_low_equal:
  ‹low_equal t1 t2
  if ‹low_equal s1 s2  t1 = snd (fst (mul_instr instr s1))  t2 = snd (fst (mul_instr instr s2))
proof -
  from that have ‹low_equal s1 s2
    and t1: t1 = snd (fst (mul_instr instr s1))
    and t2: t2 = snd (fst (mul_instr instr s2))
    by simp_all
  have f2: "s sa sb sc w sd. ¬ low_equal (s::'a sparc_state) sa  sb  snd (fst (mul_instr_sub1 sc w s))  sd  snd (fst (mul_instr_sub1 sc w sa))  low_equal sb sd"
    using mul_instr_sub1_low_equal by blast
  have f3: "s sa sb w wa wb sc. ¬ low_equal s sa  sb  snd (fst (write_reg w (wa::'a word) wb s))  sc  snd (fst (write_reg w wa wb sa))  low_equal sb sc"
    by (meson write_reg_low_equal)
  have f4: "s sa sb w c sc. ¬ low_equal (s::'a sparc_state) sa  sb  snd (fst (write_cpu w c s))  sc  snd (fst (write_cpu w c sa))  low_equal sb sc"
    by (meson write_cpu_low_equal)
  have f6: "((ucast (get_CWP (cpu_reg_val PSR s1)), s1), False) = (fst (get_curr_win () s1), snd (get_curr_win () s1))"
    by (simp add: get_curr_win_def simpler_gets_def)
  have f7: "fst (fst (get_curr_win () s1)) = fst (fst (get_curr_win () s2))"
    using ‹low_equal s1 s2 by (meson get_curr_win_low_equal)
  have "((ucast (get_CWP (cpu_reg_val PSR s2)), s2), False) = (fst (get_curr_win () s2), snd (get_curr_win () s2))"
    by (simp add: get_curr_win_def simpler_gets_def)
  then have f8: "ucast (get_CWP (cpu_reg_val PSR s2)) = fst (fst (get_curr_win () s2))  s2 = snd (fst (get_curr_win () s2))"
    by (metis prod.collapse prod.simps(1))
  then have f9: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
    using f6 ‹low_equal s1 s2 by (metis (no_types) prod.collapse prod.simps(1))
  have f10: "s sa w wa. ¬ low_equal s sa  user_reg_val (w::'a word) wa s = user_reg_val w wa sa"
    using user_reg_val_low_equal by blast
  have f11: "get_operand2 (snd instr) s1 = get_operand2 (snd instr) (snd (fst (get_curr_win () s2)))"
    using f9 f6 by (metis (no_types) get_operand2_low_equal prod.collapse prod.simps(1))
  then have f12: "uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2) = uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)"
    using f10 f9 f8 f7 by presburger
  then have f13: "(word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)  (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))  (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)  (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))  low_equal (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))"
    using f9 f4 by presburger
  have "get_operand_w5 (snd instr ! 3) = 0  low_equal (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) = write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))"
    using f10 f7 by force
  then have f14: "get_operand_w5 (snd instr ! 3)  0  low_equal (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))  ¬ low_equal (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))"
    using f3 by metis 
  then have f15: "low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  fst instr  arith_type UMULcc  get_operand_w5 (snd instr ! 3)  0  (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)  (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))  (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)  (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))"
    using f13 f12 f2 by fastforce
  have f16: "user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) = user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))"
    using f10 f9 f7 by presburger
  { assume "fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))"
    moreover
    { assume "¬ low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))"
      moreover
      { assume "low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))"
        moreover
        { assume "mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))  mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))"
          then have "write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))  fst instr  arith_type UMULcc"
            by fastforce }
        moreover
        { assume "mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))  mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))"
          then have "write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))  fst instr  arith_type UMULcc"
            by fastforce }
        ultimately have "write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))  write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))  fst instr  arith_type UMULcc"
          by force }
      ultimately have "write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))  write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))  ¬ low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  fst instr  arith_type UMULcc"
        by fastforce }
    ultimately have "fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))) = write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))  write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))) = write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))  get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))"
      by blast }
  moreover
  { assume "¬ low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))"
    moreover
    { assume "¬ low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))))))) = snd (fst (mul_instr_sub1 (arith_type UMULcc) (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))  snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))) = snd (fst (mul_instr_sub1 (arith_type UMULcc) (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))"
      then have "¬ low_equal (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))"
        using f2 by blast
      moreover
      { assume "(if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))))  (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))))"
        moreover
        { assume "(if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))))  ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))"
          then have "(if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) = (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))  get_operand_w5 (snd instr ! 3) = 0"
            by (metis f11 f16 f8) }
        ultimately have "(if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) = (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))  get_operand_w5 (snd instr ! 3) = 0"
          by fastforce }
      ultimately have "fst instr = arith_type UMULcc  (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) = (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))  get_operand_w5 (snd instr ! 3) = 0"
        using f13 f7 f3 by fastforce }
    moreover
    { assume "mul_instr_sub1 (arith_type UMULcc) (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))  mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))"
      moreover
      { assume "(if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))))  ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))"
        then have "(if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) = (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))  get_operand_w5 (snd instr ! 3) = 0"
          by (metis f11 f16 f8) }
      ultimately have "fst instr = arith_type UMULcc  (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) = (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1)) else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))  get_operand_w5 (snd instr ! 3) = 0"
        by fastforce }
    ultimately have "fst instr = arith_type UMULcc  get_operand_w5 (snd instr ! 3) = 0"
      using f12 by fastforce }
  moreover
  { assume "write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))  write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))"
    then have "fst instr = arith_type UMULcc  get_operand_w5 (snd instr ! 3) = 0"
      by presburger }
  ultimately have "fst instr = arith_type UMULcc  get_operand_w5 (snd instr ! 3) = 0  get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))"
    by force
  moreover
  { assume "fst instr  arith_type UMULcc"
    { assume "fst instr  arith_type UMULcc  low_equal (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))"
      moreover
      { assume "fst instr  arith_type UMULcc  low_equal (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))  snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))) = snd (fst (mul_instr_sub1 (arith_type UMUL) (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))"
        then have "(fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  fst instr  arith_type UMUL  fst instr  arith_type UMULcc  (get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  get_operand_w5 (snd instr ! 3) = 0"
          using f2 by presburger }
      ultimately have "fst instr  arith_type UMULcc  (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))))  ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  fst instr  arith_type UMUL  fst instr  arith_type UMULcc  (get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  get_operand_w5 (snd instr ! 3) = 0"
        by fastforce }
    then have "(get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  get_operand_w5 (snd instr ! 3) = 0"
      using f16 f11 f9 f8 f7 f4 f3 f2 by force }
  moreover
  { assume "get_operand_w5 (snd instr ! 3) = 0"
    moreover
    { assume "(fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0"
      moreover
      { assume "((fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0)  ¬ low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))"
        moreover
        { assume "((fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0)  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))"
          then have "((fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0)  arith_type UMUL  arith_type UMULcc  fst instr  arith_type UMULcc  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0"
            by fastforce
          then have "((fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0)  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  fst instr  arith_type UMULcc  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0"
            by force }
        ultimately have "((fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0)  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  ((fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0)  ¬ low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  fst instr  arith_type UMULcc  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0"
          by simp }
      ultimately have "((fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0)  ¬ low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3) = 0 then user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))) else ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))  fst instr  arith_type UMULcc  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0  (get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  (get_operand_w5 (snd instr ! 3)  0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))"
        by auto
      then have "fst instr  arith_type UMULcc  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc)  get_operand_w5 (snd instr ! 3) = 0  (get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  (get_operand_w5 (snd instr ! 3)  0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))"
        using f15 by presburger
      then have "(get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  (get_operand_w5 (snd instr ! 3)  0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))"
        using f14 f13 f12 f2 by force }
    ultimately have "(get_operand_w5 (snd instr ! 3) = 0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  (get_operand_w5 (snd instr ! 3)  0  (fst instr  arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMUL  fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))"
      using f16 f14 f11 f9 f8 f4 f2 by fastforce }
  ultimately have "(get_operand_w5 (snd instr ! 3)  0  (fst instr = arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMUL  fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))  (get_operand_w5 (snd instr ! 3) = 0  (fst instr = arith_type UMUL  low_equal (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMUL) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr = arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (arith_type UMULcc) (ucast (word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))))  (fst instr  arith_type UMUL  fst instr  arith_type UMULcc  low_equal (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))::word64) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (mul_instr_sub1 (fst instr) (ucast (word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64)) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (write_cpu (ucast ((word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))::word64) >> 32)) Y (snd (fst (get_curr_win () s2))))))))))))))"
    by blast
  moreover from t1 have
    t1 = snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3)  0 then ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) else user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1))))))) (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * uint (get_operand2 (snd instr) s1))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s1))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))) * sint (get_operand2 (snd instr) s1))) >> 32)) Y (snd (fst (get_curr_win () s1)))))))))))
    by (simp add: mul_instr_def) (simp add: simpler_gets_def bind_def h1_def h2_def Let_def case_prod_unfold)
  moreover from t2 have
    t2 = snd (fst (mul_instr_sub1 (fst instr) (ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2)))) (snd (fst (write_reg (if get_operand_w5 (snd instr ! 3)  0 then ucast (if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) else user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2))))))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3)) (snd (fst (write_cpu (ucast ((if fst instr = arith_type UMUL  fst instr = arith_type UMULcc then word_of_int (uint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * uint (get_operand2 (snd instr) s2))::word64 else word_of_int (sint (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))) * sint (get_operand2 (snd instr) s2))) >> 32)) Y (snd (fst (get_curr_win () s2)))))))))))
    by (simp add: mul_instr_def) (simp add: simpler_gets_def bind_def h1_def h2_def Let_def case_prod_unfold)
  ultimately show ?thesis
    by (simp add: mul_instr_def)
qed

lemma div_write_new_val_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (div_write_new_val i result temp_V s1)) 
t2 = snd (fst (div_write_new_val i result temp_V s2))"
shows "low_equal t1 t2"
proof (cases "(fst i)  {arith_type UDIVcc,arith_type SDIVcc}")
  case True
  then show ?thesis using a1
  apply (simp add: div_write_new_val_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (clarsimp simp add: cpu_reg_val_low_equal)
  using write_cpu_low_equal by blast
next
  case False
  then show ?thesis using a1
  apply (simp add: div_write_new_val_def)
  by (simp add: return_def)
qed

lemma div_comp_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (div_comp instr rs1 rd operand2 s1)) 
t2 = snd (fst (div_comp instr rs1 rd operand2 s2))"
shows "low_equal t1 t2"
using a1
apply (simp add: div_comp_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (clarsimp simp add: get_curr_win_low_equal)
proof -
  assume a1: "low_equal s1 s2"
  have f2: "s sa sb w wa wb sc. ¬ low_equal s sa  sb  snd (fst (write_reg w (wa::'a word) wb s))  sc  snd (fst (write_reg w wa wb sa))  low_equal sb sc"
    by (meson write_reg_low_equal)
  have f3: "gets (λs. ucast (get_CWP (cpu_reg_val PSR s))::'a word) = get_curr_win ()"
    by (simp add: get_curr_win_def)
  then have "((ucast (get_CWP (cpu_reg_val PSR s1)), s1), False) = (fst (get_curr_win () s1), snd (get_curr_win () s1))"
    by (metis (no_types) prod.collapse simpler_gets_def)
  then have f4: "ucast (get_CWP (cpu_reg_val PSR s1)) = fst (fst (get_curr_win () s1))  s1 = snd (fst (get_curr_win () s1))"
    by (metis prod.collapse prod.simps(1))
  have "((ucast (get_CWP (cpu_reg_val PSR s2)), s2), False) = (fst (get_curr_win () s2), snd (get_curr_win () s2))"
    using f3 by (metis (no_types) prod.collapse simpler_gets_def)
  then have f5: "ucast (get_CWP (cpu_reg_val PSR s2)) = fst (fst (get_curr_win () s2))  s2 = snd (fst (get_curr_win () s2))"
    by (metis (no_types) prod.collapse prod.simps(1))
  then have f6: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
    using f4 a1 by presburger
  have f7: "s sa sb p w wa sc. ¬ low_equal (s::'a sparc_state) sa  sb  snd (fst (div_write_new_val p w wa s))  sc  snd (fst (div_write_new_val p w wa sa))  low_equal sb sc"
    by (meson div_write_new_val_low_equal)
  have f8: "cpu_reg_val PSR s2 = cpu_reg_val PSR s1"
    using a1 by (simp add: cpu_reg_val_def low_equal_def)
  then have "fst (fst (get_curr_win () s2)) = ucast (get_CWP (cpu_reg_val PSR s1))"
    using f5 by presburger
  then have f9: "fst (fst (get_curr_win () s2)) = fst (fst (get_curr_win () s1))"
    using f4 by presburger
  have f10: "fst (fst (get_curr_win () s1)) = fst (fst (get_curr_win () s2))"
    using f8 f5 f4 by presburger
  have f11: "(word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))::word64) = word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))"
    using f5 f4 a1 by (metis (no_types) cpu_reg_val_def low_equal_def user_reg_val_low_equal)
  have f12: "ucast (get_CWP (cpu_reg_val PSR s1)) = fst (fst (get_curr_win () s2))"
    using f8 f5 by presburger
  then have "rd = 0  (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) = user_reg_val (ucast (get_CWP (cpu_reg_val PSR s1))) 0 (snd (fst (get_curr_win () s1)))"
    using f6 user_reg_val_low_equal by fastforce
  then have f13: "rd = 0  write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (ucast (get_CWP (cpu_reg_val PSR s1))) 0 (snd (fst (get_curr_win () s1))) = write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1)))"
    using f12 f10 by presburger
  have f14: "write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (ucast (get_CWP (cpu_reg_val PSR s1))) rd (snd (fst (get_curr_win () s2))) = write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2)))"
    using f12 f11 by auto
  have "write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (ucast (get_CWP (cpu_reg_val PSR s1))) rd (snd (fst (get_curr_win () s1))) = write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1)))  write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (ucast (get_CWP (cpu_reg_val PSR s1))) rd (snd (fst (get_curr_win () s2))) = write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2)))  low_equal (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))))))"
    using f6 f2 by metis
  moreover
  { assume "low_equal (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))))))"
    then have "low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2)))))))))"
      using f11 f9 f7 by metis 
    moreover
    { assume "low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2)))))))))  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2)))))))))"
      then have "div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2) = (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2))  rd = 0"
        by fastforce }
    ultimately have "div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2) = (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2))  rd = 0  (rd  0  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))))))))))  (rd = 0  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))))))"
      by fastforce }
  moreover
  { assume "write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (ucast (get_CWP (cpu_reg_val PSR s1))) rd (snd (fst (get_curr_win () s1)))  write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1)))"
    then have "div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)  (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2))"
      using f12 f9 by fastforce }
  moreover
  { assume "write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (ucast (get_CWP (cpu_reg_val PSR s1))) rd (snd (fst (get_curr_win () s2)))  write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2)))"
    then have "rd = 0"
      using f14 by presburger }
  moreover
  { assume "rd = 0"
    then have "rd = 0  low_equal (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))))))"
      using f13 f12 f6 f2 by metis 
    then have "rd = 0  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s1))) rd (snd (fst (get_curr_win () s1))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s1))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (if rd = 0 then user_reg_val (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))) else div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2)))))))))"
      using f11 f9 f7 by metis 
    then have "(rd  0  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))))))))))  (rd = 0  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))))))"
      using f10 by fastforce }
  ultimately show "(rd  0  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (fst (fst (get_curr_win () s2))) rd (snd (fst (get_curr_win () s2))))))))))  (rd = 0  low_equal (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s1))))) operand2 >> 31))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s1))))))))) (snd (fst (div_write_new_val instr (div_comp_result instr (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2)) (div_comp_temp_V instr (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 32)) (ucast (div_comp_temp_64bit instr (word_cat (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (user_reg_val (fst (fst (get_curr_win () s2))) rs1 (snd (fst (get_curr_win () s2))))) operand2 >> 31))) (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0 (snd (fst (get_curr_win () s2))))))))))"
    using f9 by fastforce
qed

lemma div_instr_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (div_instr instr s1))  t2 = snd (fst (div_instr instr s2))"
shows "low_equal t1 t2"
using a1
apply (simp add: div_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp add: return_def)
apply (auto simp add: get_operand2_low_equal)
 apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
 apply (auto simp add: traps_low_equal)
 apply (blast intro: mod_trap_low_equal)
using div_comp_low_equal by blast

lemma get_curr_win_traps_low_equal: 
assumes a1: "low_equal s1 s2"
shows "low_equal
(snd (fst (get_curr_win () s1))
  traps := insert some_trap (traps (snd (fst (get_curr_win () s1)))))
(snd (fst (get_curr_win () s2))
  traps := insert some_trap (traps (snd (fst (get_curr_win () s2)))))"
proof -
  from a1 have f1: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
    using get_curr_win2_low_equal by auto
  then have f2: "(traps (snd (fst (get_curr_win () s1)))) = 
    (traps (snd (fst (get_curr_win () s2))))"
    using traps_low_equal by auto
  then show ?thesis using f1 f2 mod_trap_low_equal
  by fastforce
qed

lemma save_restore_instr_sub1_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (save_retore_sub1 result new_cwp rd s1))  
t2 = snd (fst (save_retore_sub1 result new_cwp rd s2))"
shows "low_equal t1 t2"
using a1
apply (simp add: save_retore_sub1_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (auto simp add: cpu_reg_val_low_equal)
using write_cpu_low_equal write_reg_low_equal
by fastforce

lemma get_WIM_bit_low_equal: 
  ‹get_WIM_bit (nat ((uint (fst (fst (get_curr_win () s1))) - 1) mod NWINDOWS))
     (cpu_reg_val WIM (snd (fst (get_curr_win () s1)))) =
    get_WIM_bit (nat ((uint (fst (fst (get_curr_win () s2))) - 1) mod NWINDOWS))
     (cpu_reg_val WIM (snd (fst (get_curr_win () s2))))
  if ‹low_equal s1 s2
proof -
  from that have f1: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
  using get_curr_win2_low_equal by blast
  then have f2: "(cpu_reg_val WIM (snd (fst (get_curr_win () s1)))) =
    (cpu_reg_val WIM (snd (fst (get_curr_win () s2))))"
  using cpu_reg_val_low_equal by auto
  from that have "(fst (fst (get_curr_win () s1))) = (fst (fst (get_curr_win () s2)))"
  using get_curr_win_low_equal by auto
  then show ?thesis using f1 f2
    by auto
qed

lemma get_WIM_bit_low_equal2: 
  ‹get_WIM_bit (nat ((uint (fst (fst (get_curr_win () s1))) + 1) mod NWINDOWS))
    (cpu_reg_val WIM (snd (fst (get_curr_win () s1)))) =
    get_WIM_bit (nat ((uint (fst (fst (get_curr_win () s2))) + 1) mod NWINDOWS))
      (cpu_reg_val WIM (snd (fst (get_curr_win () s2))))
  if ‹low_equal s1 s2
proof -
  from that have f1: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
  using get_curr_win2_low_equal by blast
  then have f2: "(cpu_reg_val WIM (snd (fst (get_curr_win () s1)))) =
    (cpu_reg_val WIM (snd (fst (get_curr_win () s2))))"
  using cpu_reg_val_low_equal by auto
  from that have "(fst (fst (get_curr_win () s1))) = (fst (fst (get_curr_win () s2)))"
  using get_curr_win_low_equal by auto
  then show ?thesis using f1 f2
  by auto 
qed

lemma take_bit_5_mod_NWINDOWS_eq [simp]:
  ‹take_bit 5 (k mod NWINDOWS) = k mod NWINDOWS›
  by (simp add: NWINDOWS_def take_bit_eq_mod)

lemma save_restore_instr_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (save_restore_instr instr s1))  t2 = snd (fst (save_restore_instr instr s2))"
shows "low_equal t1 t2"
proof (cases "fst instr = ctrl_type SAVE")
  case True
  then have f1: "fst instr = ctrl_type SAVE" by auto
  then show ?thesis using a1
  apply (simp add: save_restore_instr_def)
  apply (simp add: Let_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply auto
     apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
     apply (simp add: get_curr_win_traps_low_equal)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
    apply (simp add: get_WIM_bit_low_equal)
   apply (simp add: get_WIM_bit_low_equal)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: get_curr_win_low_equal)
  using get_curr_win2_low_equal save_restore_instr_sub1_low_equal get_addr2_low_equal
  apply metis
  done
next
  case False
  then show ?thesis using a1
  apply (simp add: save_restore_instr_def)
  apply (simp add: Let_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply auto
     apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
     apply (simp add: get_curr_win_traps_low_equal)
    apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
    apply (simp add: get_WIM_bit_low_equal2)
   apply (simp add: get_WIM_bit_low_equal2)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: get_curr_win_low_equal)
  using get_curr_win2_low_equal save_restore_instr_sub1_low_equal get_addr2_low_equal
  by metis 
qed

lemma call_instr_low_equal: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (call_instr instr s1))  t2 = snd (fst (call_instr instr s2))"
shows "low_equal t1 t2"
using a1
apply (simp add: call_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (auto simp add: get_curr_win_low_equal)
using cpu_reg_val_low_equal get_curr_win2_low_equal
write_cpu_low_equal write_reg_low_equal
proof -
  assume a1: "low_equal s1 s2"
  assume "t1 = snd (fst (write_cpu (cpu_reg_val PC (snd (fst (get_curr_win () s1))) + (ucast (get_operand_w30 (snd instr ! 0)) << 2)) nPC (snd (fst (write_cpu (cpu_reg_val nPC (snd (fst (get_curr_win () s1)))) PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 15 (snd (fst (get_curr_win () s1)))))))))))"
  assume "t2 = snd (fst (write_cpu (cpu_reg_val PC (snd (fst (get_curr_win () s2))) + (ucast (get_operand_w30 (snd instr ! 0)) << 2)) nPC (snd (fst (write_cpu (cpu_reg_val nPC (snd (fst (get_curr_win () s2)))) PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 15 (snd (fst (get_curr_win () s2)))))))))))"
  have "c. cpu_reg_val c (snd (fst (get_curr_win () s1))) = cpu_reg_val c (snd (fst (get_curr_win () s2)))"
    using a1 by (meson cpu_reg_val_low_equal get_curr_win2_low_equal)
  then show "low_equal (snd (fst (write_cpu (cpu_reg_val PC (snd (fst (get_curr_win () s1))) + (ucast (get_operand_w30 (snd instr ! 0)) << 2)) nPC (snd (fst (write_cpu (cpu_reg_val nPC (snd (fst (get_curr_win () s1)))) PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 15 (snd (fst (get_curr_win () s1)))))))))))) (snd (fst (write_cpu (cpu_reg_val PC (snd (fst (get_curr_win () s2))) + (ucast (get_operand_w30 (snd instr ! 0)) << 2)) nPC (snd (fst (write_cpu (cpu_reg_val nPC (snd (fst (get_curr_win () s2)))) PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 15 (snd (fst (get_curr_win () s2))))))))))))"
    using a1 by (metis (no_types) get_curr_win2_low_equal write_cpu_low_equal write_reg_low_equal)
qed

lemma jmpl_instr_low_equal_sub1: 
assumes a1: "low_equal s1 s2 
t1 = snd (fst (write_cpu (get_addr (snd instr) (snd (fst (get_curr_win () s2)))) nPC
  (snd (fst (write_cpu (cpu_reg_val nPC 
  (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1))))
  (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
  (snd (fst (get_curr_win () s1)))))))
  PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1))))
  (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
  (snd (fst (get_curr_win () s1))))))))))) 
t2 = snd (fst (write_cpu (get_addr (snd instr) (snd (fst (get_curr_win () s2)))) nPC
  (snd (fst (write_cpu (cpu_reg_val nPC
  (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2))))
  (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
  (snd (fst (get_curr_win () s2)))))))
  PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2))))
  (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
  (snd (fst (get_curr_win () s2)))))))))))"
shows "low_equal t1 t2"
proof -
  from a1 have f1: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
  using get_curr_win2_low_equal by blast
  then have f2: "(cpu_reg_val PC (snd (fst (get_curr_win () s1)))) =
    (cpu_reg_val PC (snd (fst (get_curr_win () s2))))"
  using cpu_reg_val_low_equal by blast
  then have f3: "low_equal 
    (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s1))))))
    (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s2))))))"
  using f1 write_reg_low_equal by fastforce
  then have "(cpu_reg_val nPC 
    (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s1))))))) =
    (cpu_reg_val nPC
    (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s2)))))))"
  using cpu_reg_val_low_equal by auto
  then have f4: "low_equal
    (snd (fst (write_cpu (cpu_reg_val nPC 
    (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s1)))))))
    PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s1))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s1)))))))))
    (snd (fst (write_cpu (cpu_reg_val nPC
    (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s2)))))))
    PC (snd (fst (write_reg (cpu_reg_val PC (snd (fst (get_curr_win () s2))))
    (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! 3))
    (snd (fst (get_curr_win () s2)))))))))"
  using f3 write_cpu_low_equal by fastforce
  then show ?thesis using write_cpu_low_equal
  using assms by blast  
qed

lemma jmpl_instr_low_equal_sub2:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (write_cpu (get_addr (snd instr) (snd (fst (get_curr_win () s2)))) nPC
  (snd (fst (write_cpu (cpu_reg_val nPC
  (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s1))))))) PC (snd (fst (write_reg
  (user_reg_val (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s1))))))))))) 
t2 = snd (fst (write_cpu (get_addr (snd instr) (snd (fst (get_curr_win () s2)))) nPC
  (snd (fst (write_cpu (cpu_reg_val nPC (snd (fst (write_reg
  (user_reg_val (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s2))))))) PC (snd (fst (write_reg
  (user_reg_val (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0
  (snd (fst (get_curr_win () s2)))))))))))"
shows "low_equal t1 t2"
proof -
  from a1 have f1: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
  using get_curr_win2_low_equal by blast
  then have f2: "(user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1)))) = 
    (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2))))"
  using user_reg_val_low_equal by blast
  then have f3: "low_equal 
    (snd (fst (write_reg
    (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1))))))
    (snd (fst (write_reg
    (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2))))))"
  using f1 write_reg_low_equal by fastforce
  then have "(cpu_reg_val nPC
    (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1))))))) = 
    (cpu_reg_val nPC (snd (fst (write_reg
    (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2)))))))"
  using cpu_reg_val_low_equal by blast
  then have "low_equal 
    (snd (fst (write_cpu (cpu_reg_val nPC
    (snd (fst (write_reg (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1))))))) PC (snd (fst (write_reg
    (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s1)))))))))
    (snd (fst (write_cpu (cpu_reg_val nPC (snd (fst (write_reg
    (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2))))))) PC (snd (fst (write_reg
    (user_reg_val (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) 0
    (snd (fst (get_curr_win () s2)))))))))"
  using f1 f2 f3 write_cpu_low_equal by fastforce
  then show ?thesis 
  using write_cpu_low_equal
  using assms by blast 
qed

lemma jmpl_instr_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (jmpl_instr instr s1))  t2 = snd (fst (jmpl_instr instr s2))"
shows "low_equal t1 t2"
using a1
apply (simp add: jmpl_instr_def)
apply (simp add: Let_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply auto
   apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
   apply (simp add: get_curr_win_traps_low_equal)
  apply (simp add: get_addr2_low_equal)
 apply (simp add: get_addr2_low_equal)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (simp_all add: get_addr2_low_equal)
apply (simp_all add: get_curr_win_low_equal)
apply (case_tac "get_operand_w5 (snd instr ! 3)  0")
apply auto
 using jmpl_instr_low_equal_sub1 apply blast
apply (simp_all add: get_curr_win_low_equal)
using jmpl_instr_low_equal_sub2 by blast

lemma rett_instr_low_equal:
assumes a1: "low_equal s1 s2 
¬ snd (rett_instr instr s1) 
¬ snd (rett_instr instr s2) 
(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
t1 = snd (fst (rett_instr instr s1))  t2 = snd (fst (rett_instr instr s2))"
shows "low_equal t1 t2"
using a1
apply (simp add: rett_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
apply auto
   apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
   apply (simp add: return_def)
   using mod_trap_low_equal traps_low_equal apply fastforce
  using cpu_reg_val_low_equal apply fastforce
 using cpu_reg_val_low_equal apply fastforce
apply (simp add: bind_def h1_def h2_def Let_def)
by (simp add: case_prod_unfold fail_def)

lemma read_state_reg_low_equal:
assumes a1: "low_equal s1 s2 
(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
t1 = snd (fst (read_state_reg_instr instr s1))  
t2 = snd (fst (read_state_reg_instr instr s2))"
shows "low_equal t1 t2"
proof (cases "(fst instr  {sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR}  
        (fst instr = sreg_type RDASR  privileged_ASR (get_operand_w5 ((snd instr)!0))))")
  case True   
  then have "(fst instr  {sreg_type RDPSR,sreg_type RDWIM,sreg_type RDTBR}  
        (fst instr = sreg_type RDASR  privileged_ASR (get_operand_w5 ((snd instr)!0))))
         (((get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s1))))))::word1) = 0
         (((get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s2))))))::word1) = 0"
    by (metis assms get_curr_win_privilege)
  then show ?thesis using a1
  apply (simp add: read_state_reg_instr_def)
  apply (simp add: Let_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (simp add: case_prod_unfold)
  apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
  apply clarsimp
  using get_curr_win_traps_low_equal
  by auto  
next
  case False
  then have f1: "¬((fst instr = sreg_type RDPSR 
                    fst instr = sreg_type RDWIM 
                    fst instr = sreg_type RDTBR 
                    fst instr = sreg_type RDASR  privileged_ASR (get_operand_w5 (snd instr ! 0))))"
    by blast 
  then show ?thesis 
  proof (cases "illegal_instruction_ASR (get_operand_w5 ((snd instr)!0))")
    case True
    then show ?thesis using a1 f1
    apply read_state_reg_instr_privilege_proof
    by (simp add: illegal_instruction_ASR_def)    
  next
    case False
    then have f2: "¬(illegal_instruction_ASR (get_operand_w5 ((snd instr)!0)))" 
      by auto
    then show ?thesis 
    proof (cases "(get_operand_w5 ((snd instr)!1))  0")
      case True
      then have f3: "(get_operand_w5 ((snd instr)!1))  0" 
        by auto
      then show ?thesis 
      proof (cases "fst instr = sreg_type RDY")
        case True
        then show ?thesis using a1 f1 f2 f3
        apply (simp add: read_state_reg_instr_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: case_prod_unfold)
        apply (auto simp add: get_curr_win_low_equal)
        using cpu_reg_val_low_equal get_curr_win2_low_equal write_reg_low_equal
        proof -
          assume "low_equal s1 s2"
          then have "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
            by (meson get_curr_win2_low_equal)
          then show "low_equal (snd (fst (write_reg (cpu_reg_val Y (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (cpu_reg_val Y (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))))))"
            using cpu_reg_val_low_equal write_reg_low_equal by fastforce
        qed
      next
        case False
        then have f4: "¬(fst instr = sreg_type RDY)" by auto
        then show ?thesis 
        proof (cases "fst instr = sreg_type RDASR")
          case True
          then show ?thesis using a1 f1 f2 f3 f4
          apply read_state_reg_instr_privilege_proof
          apply (clarsimp simp add: get_curr_win_low_equal)
          using cpu_reg_val_low_equal get_curr_win2_low_equal write_reg_low_equal
          proof -
            assume a1: "low_equal s1 s2"
            then have "cpu_reg_val (ASR (get_operand_w5 (snd instr ! 0))) (snd (fst (get_curr_win () s1))) = cpu_reg_val (ASR (get_operand_w5 (snd instr ! 0))) (snd (fst (get_curr_win () s2)))"
              by (meson cpu_reg_val_low_equal get_curr_win2_low_equal)
            then show "low_equal (snd (fst (write_reg (cpu_reg_val (ASR (get_operand_w5 (snd instr ! 0))) (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (cpu_reg_val (ASR (get_operand_w5 (snd instr ! 0))) (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))))))"
              using a1 by (metis (no_types) get_curr_win2_low_equal write_reg_low_equal)
          qed
        next
          case False
          then have f5: "¬(fst instr = sreg_type RDASR)" by auto
          then show ?thesis using a1 f1 f2 f3 f4 f5
          apply read_state_reg_instr_privilege_proof
          apply (clarsimp simp add: get_curr_win_low_equal)
          using cpu_reg_val_low_equal get_curr_win2_low_equal write_reg_low_equal
          proof -
            assume a1: "low_equal s1 s2"
            assume a2: "t1 = snd (fst (write_reg (cpu_reg_val TBR (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))))"
            assume "t2 = snd (fst (write_reg (cpu_reg_val TBR (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2)))))"
            have "s. ¬ low_equal (snd (fst (get_curr_win () s1))) s  snd (fst (write_reg (cpu_reg_val TBR s) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))))) = t1"
              using a2 by (simp add: cpu_reg_val_low_equal)
            then show "low_equal (snd (fst (write_reg (cpu_reg_val TBR (snd (fst (get_curr_win () s1)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1)))))) (snd (fst (write_reg (cpu_reg_val TBR (snd (fst (get_curr_win () s2)))) (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))))))"
              using a2 a1 by (metis (no_types) get_curr_win2_low_equal write_reg_low_equal)
          qed
        qed
      qed
    next
      case False
      then show ?thesis using a1 f1 f2
      apply (simp add: read_state_reg_instr_def)
      apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
      apply (simp add: return_def) 
      apply clarsimp
      apply (simp add: case_prod_unfold)
      using get_curr_win2_low_equal by auto
    qed
  qed
qed

lemma get_s_get_curr_win:
assumes a1: "low_equal s1 s2"
shows "get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))) =
get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s2))))"
proof - 
  from a1 have "low_equal (snd (fst (get_curr_win () s1))) 
    (snd (fst (get_curr_win () s2)))"
  using get_curr_win2_low_equal by blast
  then show ?thesis
  using cpu_reg_val_low_equal
  by fastforce  
qed

lemma write_state_reg_low_equal:
assumes a1: "low_equal s1 s2 
(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
t1 = snd (fst (write_state_reg_instr instr s1)) 
t2 = snd (fst (write_state_reg_instr instr s2))"
shows "low_equal t1 t2"
proof (cases "fst instr = sreg_type WRY")
  case True
  then show ?thesis using a1
  apply write_state_reg_instr_privilege_proof
  apply (simp add: simpler_modify_def)
  apply (simp add: delayed_pool_add_def DELAYNUM_def)
  apply (auto simp add: get_curr_win_low_equal)
  using get_curr_win2_low_equal cpu_reg_mod_low_equal
  user_reg_val_low_equal get_operand2_low_equal
  proof -
    assume a1: "low_equal s1 s2"
    assume "t2 = cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s2)))) Y (snd (fst (get_curr_win () s2)))"
    assume "t1 = cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s1)))) Y (snd (fst (get_curr_win () s1)))"
    have f2: "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
      using a1 by (meson get_curr_win2_low_equal)
    then have f3: "w wa. user_reg_val w wa (snd (fst (get_curr_win () s2))) = user_reg_val w wa (snd (fst (get_curr_win () s1)))"
      by (simp add: user_reg_val_low_equal)
    have "is. get_operand2 is (snd (fst (get_curr_win () s2))) = get_operand2 is (snd (fst (get_curr_win () s1)))"
      using f2 by (simp add: get_operand2_low_equal)
    then show "low_equal (cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s1)))) Y (snd (fst (get_curr_win () s1)))) (cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s2)))) Y (snd (fst (get_curr_win () s2))))"
      using f3 f2 by (metis cpu_reg_mod_low_equal)
  qed
next
  case False
  then have f1: "¬(fst instr = sreg_type WRY)" by auto
  then show ?thesis
  proof (cases "fst instr = sreg_type WRASR")
    case True
    then have f1_1: "fst instr = sreg_type WRASR" by auto
    then show ?thesis
    proof (cases "privileged_ASR (get_operand_w5 (snd instr ! 3)) 
                  get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))) = 0")
      case True
      then show ?thesis using a1 f1 f1_1
      apply write_state_reg_instr_privilege_proof
      apply (clarsimp simp add: get_s_get_curr_win)
      apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
      apply (clarsimp simp add: get_curr_win3_low_equal)
      using traps_low_equal mod_trap_low_equal get_curr_win2_low_equal
      by fastforce
    next
      case False
      then have f1_2: "¬ (privileged_ASR (get_operand_w5 (snd instr ! 3)) 
      get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))) = 0)"
      by auto
      then show ?thesis
      proof (cases "illegal_instruction_ASR (get_operand_w5 (snd instr ! 3))")
        case True
        then show ?thesis using a1 f1 f1_1 f1_2
        apply write_state_reg_instr_privilege_proof
        apply (clarsimp simp add: get_s_get_curr_win)
        apply auto
         apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
         apply (clarsimp simp add: get_curr_win3_low_equal)
         using traps_low_equal mod_trap_low_equal get_curr_win2_low_equal
         apply fastforce
        apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
        apply (clarsimp simp add: get_curr_win3_low_equal)
        using traps_low_equal mod_trap_low_equal get_curr_win2_low_equal
        by fastforce
      next
        case False
        then show ?thesis using a1 f1 f1_1 f1_2
        apply write_state_reg_instr_privilege_proof
        apply (clarsimp simp add: get_s_get_curr_win)
        apply auto
         apply (simp add: simpler_modify_def)
         apply (simp add: delayed_pool_add_def DELAYNUM_def)
         apply (auto simp add: get_curr_win_low_equal)      
         using get_curr_win2_low_equal cpu_reg_mod_low_equal
         user_reg_val_low_equal get_operand2_low_equal
         proof -
           assume a1: "low_equal s1 s2"
           assume "t2 = cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s2)))) (ASR (get_operand_w5 (snd instr ! 3))) (snd (fst (get_curr_win () s2)))"
           assume "t1 = cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s1)))) (ASR (get_operand_w5 (snd instr ! 3))) (snd (fst (get_curr_win () s1)))"
           have "low_equal (snd (fst (get_curr_win () s1))) (snd (fst (get_curr_win () s2)))"
            using a1 by (meson get_curr_win2_low_equal)
           then show "low_equal (cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s1))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s1)))) (ASR (get_operand_w5 (snd instr ! 3))) (snd (fst (get_curr_win () s1)))) (cpu_reg_mod (user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0)) (snd (fst (get_curr_win () s2))) XOR get_operand2 (snd instr) (snd (fst (get_curr_win () s2)))) (ASR (get_operand_w5 (snd instr ! 3))) (snd (fst (get_curr_win () s2))))"
            using cpu_reg_mod_low_equal get_operand2_low_equal user_reg_val_low_equal by fastforce
         next
           assume f1: "¬ illegal_instruction_ASR (get_operand_w5 (snd instr ! 3))"
           assume f2: "fst instr = sreg_type WRASR"
           assume f3: "snd (fst (write_state_reg_instr instr s1)) =
    snd (fst (modify
               (delayed_pool_add
                 (DELAYNUM,
                  user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s1))) XOR
                  get_operand2 (snd instr) (snd (fst (get_curr_win () s1))),
                  ASR (get_operand_w5 (snd instr ! 3))))
               (snd (fst (get_curr_win () s1))))) "
           assume f4: "snd (fst (write_state_reg_instr instr s2)) =
    snd (fst (modify
               (delayed_pool_add
                 (DELAYNUM,
                  user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                   (snd (fst (get_curr_win () s2))) XOR
                  get_operand2 (snd instr) (snd (fst (get_curr_win () s2))),
                  ASR (get_operand_w5 (snd instr ! 3))))
               (snd (fst (get_curr_win () s2)))))"
           assume f5: "low_equal s1 s2"
           assume f6: "(get_S (cpu_reg_val PSR s1)) = 0"
           assume f7: "(get_S (cpu_reg_val PSR s2)) = 0"
           assume f8: "t1 = snd (fst (modify
                    (delayed_pool_add
                      (DELAYNUM,
                       user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                        (snd (fst (get_curr_win () s1))) XOR
                       get_operand2 (snd instr) (snd (fst (get_curr_win () s1))),
                       ASR (get_operand_w5 (snd instr ! 3))))
                    (snd (fst (get_curr_win () s1)))))"
           assume f9: "t2 = snd (fst (modify
                    (delayed_pool_add
                      (DELAYNUM,
                       user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                        (snd (fst (get_curr_win () s2))) XOR
                       get_operand2 (snd instr) (snd (fst (get_curr_win () s2))),
                       ASR (get_operand_w5 (snd instr ! 3))))
                    (snd (fst (get_curr_win () s2)))))"
           assume f10: "get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s2))))  0"
           assume f11: "(s1 s2 t1 t2.
            low_equal s1 s2 
            t1 = snd (fst (get_curr_win () s1))  t2 = snd (fst (get_curr_win () s2))  low_equal t1 t2)"
           assume f12: "(s1 s2 t1 w cr t2.
            low_equal s1 s2  t1 = cpu_reg_mod w cr s1  t2 = cpu_reg_mod w cr s2  low_equal t1 t2)"
           assume f13: "(s1 s2 win ur. low_equal s1 s2  user_reg_val win ur s1 = user_reg_val win ur s2)"
           assume f14: "(s1 s2 op_list. low_equal s1 s2  get_operand2 op_list s1 = get_operand2 op_list s2)"
           show "low_equal
     (snd (fst (modify
                 (delayed_pool_add
                   (DELAYNUM,
                    user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                     (snd (fst (get_curr_win () s1))) XOR
                    get_operand2 (snd instr) (snd (fst (get_curr_win () s1))),
                    ASR (get_operand_w5 (snd instr ! 3))))
                 (snd (fst (get_curr_win () s1))))))
     (snd (fst (modify
                 (delayed_pool_add
                   (DELAYNUM,
                    user_reg_val (fst (fst (get_curr_win () s2))) (get_operand_w5 (snd instr ! Suc 0))
                     (snd (fst (get_curr_win () s2))) XOR
                    get_operand2 (snd instr) (snd (fst (get_curr_win () s2))),
                    ASR (get_operand_w5 (snd instr ! 3))))
                 (snd (fst (get_curr_win () s2))))))"
           using f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14
           using Sparc_Properties.ucast_0 assms get_curr_win_privilege by blast            
         qed
      qed
    qed
  next
    case False
    then have f2: "¬(fst instr = sreg_type WRASR)" by auto
    have f3: "get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s1)))) = 0 
      get_S (cpu_reg_val PSR (snd (fst (get_curr_win () s2)))) = 0"
      using get_curr_win_privilege a1 by (metis ucast_id)
    then show ?thesis 
    proof (cases "fst instr = sreg_type WRPSR")
      case True
      then show ?thesis using a1 f1 f2 f3
      apply write_state_reg_instr_privilege_proof
      apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
      apply (clarsimp simp add: get_curr_win3_low_equal)
      using traps_low_equal mod_trap_low_equal get_curr_win2_low_equal
      by fastforce      
    next
      case False
      then have f4: "¬(fst instr = sreg_type WRPSR)" by auto
      then show ?thesis 
      proof (cases "fst instr = sreg_type WRWIM")  
        case True
        then show ?thesis using a1 f1 f2 f3 f4
        apply write_state_reg_instr_privilege_proof
        apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
        apply (clarsimp simp add: get_curr_win3_low_equal)
        using traps_low_equal mod_trap_low_equal get_curr_win2_low_equal
        by fastforce 
      next
        case False
        then have f5: "¬(fst instr = sreg_type WRWIM)" by auto
        then show ?thesis using a1 f1 f2 f3 f4 f5
        apply write_state_reg_instr_privilege_proof
        apply (simp add: raise_trap_def add_trap_set_def simpler_modify_def)
        apply (clarsimp simp add: get_curr_win3_low_equal)
        using traps_low_equal mod_trap_low_equal get_curr_win2_low_equal
        by fastforce        
      qed
    qed
  qed
qed

lemma flush_instr_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (flush_instr instr s1)) 
t2 = snd (fst (flush_instr instr s2))"
shows "low_equal t1 t2"
using a1
apply (simp add: flush_instr_def)
apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def simpler_modify_def)
apply (simp add: flush_cache_all_def)
apply (simp add: low_equal_def)
apply (simp add: user_accessible_def)
apply (simp add: mem_equal_def)
by auto

lemma branch_instr_sub1_low_equal:
assumes a1: "low_equal s1 s2"
shows "branch_instr_sub1 instr_name s1 = branch_instr_sub1 instr_name s2"
using a1 apply (simp add: branch_instr_sub1_def)
by (simp add: low_equal_def)

lemma set_annul_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (set_annul True s1)) 
t2 = snd (fst (set_annul True s2))"
shows "low_equal t1 t2"
using a1 apply (simp add: set_annul_def)
apply (simp add: simpler_modify_def annul_mod_def)
using state_var2_low_equal state_var_low_equal 
by fastforce

lemma branch_instr_low_equal_sub0:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (write_cpu (cpu_reg_val PC s2 +
  sign_ext24 (ucast (get_operand_w22 (snd instr ! Suc 0)) << 2))
  nPC (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s1))))) 
t2 = snd (fst (write_cpu (cpu_reg_val PC s2 +
  sign_ext24 (ucast (get_operand_w22 (snd instr ! Suc 0)) << 2))
  nPC (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s2)))))"
shows "low_equal t1 t2"
proof -
  from a1 have "low_equal
    (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s1)))
    (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s2)))"
  using write_cpu_low_equal by blast
  then show ?thesis
  using a1 write_cpu_low_equal by blast
qed

lemma branch_instr_low_equal_sub1:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (set_annul True (snd (fst (write_cpu
  (cpu_reg_val PC s2 + sign_ext24
  (ucast (get_operand_w22 (snd instr ! Suc 0)) << 2))
  nPC (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s1)))))))) 
t2 = snd (fst (set_annul True (snd (fst (write_cpu
  (cpu_reg_val PC s2 + sign_ext24
  (ucast (get_operand_w22 (snd instr ! Suc 0)) << 2))
  nPC (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s2))))))))"
shows "low_equal t1 t2"
proof -
  from a1 have "low_equal 
    (snd (fst (write_cpu
    (cpu_reg_val PC s2 + sign_ext24
    (ucast (get_operand_w22 (snd instr ! Suc 0)) << 2))
    nPC (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s1))))))
    (snd (fst (write_cpu
    (cpu_reg_val PC s2 + sign_ext24
    (ucast (get_operand_w22 (snd instr ! Suc 0)) << 2))
    nPC (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s2))))))"
  using branch_instr_low_equal_sub0 by blast  
  then show ?thesis using a1
  using set_annul_low_equal by blast  
qed

lemma branch_instr_low_equal_sub2:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (set_annul True
  (snd (fst (write_cpu (cpu_reg_val nPC s2 + 4) nPC
  (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s1)))))))) 
t2 = snd (fst (set_annul True
  (snd (fst (write_cpu (cpu_reg_val nPC s2 + 4) nPC
   (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s2))))))))"
shows "low_equal t1 t2"
proof -
  from a1 have "low_equal
    (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s1)))
    (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s2)))"
  using write_cpu_low_equal by blast
  then have "low_equal 
    (snd (fst (write_cpu (cpu_reg_val nPC s2 + 4) nPC
    (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s1))))))
    (snd (fst (write_cpu (cpu_reg_val nPC s2 + 4) nPC
    (snd (fst (write_cpu (cpu_reg_val nPC s2) PC s2))))))"
  using write_cpu_low_equal by blast
  then show ?thesis using a1
  using set_annul_low_equal by blast
qed

lemma branch_instr_low_equal:
assumes a1: "low_equal s1 s2 
t1 = snd (fst (branch_instr instr s1)) 
t2 = snd (fst (branch_instr instr s2))"
shows "low_equal t1 t2"
using a1 
apply (simp add: branch_instr_def)
apply (simp add: Let_def simpler_gets_def bind_def h1_def h2_def)
apply (simp add: case_prod_unfold return_def)
apply clarsimp
apply (simp add: branch_instr_sub1_low_equal)
apply (simp_all add: cpu_reg_val_low_equal)
apply (cases "branch_instr_sub1 (fst instr) s2 = 1")
 apply clarsimp
 apply (simp add: bind_def h1_def h2_def Let_def)
 apply (simp_all add: cpu_reg_val_low_equal)
 apply (simp add: case_prod_unfold)
 apply (cases "fst instr = bicc_type BA  get_operand_flag (snd instr ! 0) = 1")
  apply clarsimp
  using branch_instr_low_equal_sub1 apply blast
 apply clarsimp
 apply (simp add: return_def)
 using branch_instr_low_equal_sub0 apply fastforce
apply (simp add: bind_def h1_def h2_def Let_def)
apply (simp add: case_prod_unfold)
apply (cases "get_operand_flag (snd instr ! 0) = 1")
 apply clarsimp
 apply (simp_all add: cpu_reg_val_low_equal)
 using branch_instr_low_equal_sub2 apply metis
apply (simp add: return_def)
using write_cpu_low_equal by metis

lemma dispath_instr_low_equal:
assumes a1: "low_equal s1 s2 
(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
¬ snd (dispatch_instruction instr s1) 
¬ snd (dispatch_instruction instr s2) 
t1 = (snd (fst (dispatch_instruction instr s1))) 
t2 = (snd (fst (dispatch_instruction instr s2)))"
shows "low_equal t1 t2"
proof (cases "get_trap_set s1 = {}")
  case True
  then have f_no_traps: "get_trap_set s1 = {}  get_trap_set s2 = {}"
    using a1 by (simp add: low_equal_def get_trap_set_def)
  then show ?thesis
  proof (cases "fst instr  {load_store_type LDSB,load_store_type LDUB,
        load_store_type LDUBA,load_store_type LDUH,load_store_type LD,
        load_store_type LDA,load_store_type LDD}")
    case True
    then show ?thesis using a1 f_no_traps
    apply dispath_instr_privilege_proof
    by (blast intro: load_instr_low_equal)
  next
    case False
    then have f1: "fst instr  {load_store_type LDSB, load_store_type LDUB, 
      load_store_type LDUBA, load_store_type LDUH,
      load_store_type LD, load_store_type LDA, load_store_type LDD}" 
      by auto
    then show ?thesis 
    proof (cases "fst instr  {load_store_type STB,load_store_type STH,
        load_store_type ST,load_store_type STA,load_store_type STD}")
      case True
      then show ?thesis using a1 f_no_traps f1
      apply dispath_instr_privilege_proof
      using store_instr_low_equal by blast      
    next
      case False
      then have f2: "¬(fst instr  {load_store_type STB,load_store_type STH,
        load_store_type ST,load_store_type STA,load_store_type STD})"
        by auto
      then show ?thesis 
      proof (cases "fst instr  {sethi_type SETHI}")
        case True
        then show ?thesis using a1 f_no_traps f1 f2
        apply dispath_instr_privilege_proof
        by (auto intro: sethi_low_equal)        
      next
        case False
        then have f3: "¬(fst instr  {sethi_type SETHI})"
          by auto
        then show ?thesis 
        proof (cases "fst instr  {nop_type NOP}")
          case True
          then show ?thesis using a1 f_no_traps f1 f2 f3
          apply dispath_instr_privilege_proof
          by (auto intro: nop_low_equal)
        next
          case False
          then have f4: "¬(fst instr  {nop_type NOP})" 
            by auto
          then show ?thesis 
          proof (cases "fst instr  {logic_type ANDs,logic_type ANDcc,logic_type ANDN,
            logic_type ANDNcc,logic_type ORs,logic_type ORcc,logic_type ORN,
            logic_type XORs,logic_type XNOR}")
            case True
            then show ?thesis using a1 f_no_traps f1 f2 f3 f4
            apply dispath_instr_privilege_proof
            using logical_instr_low_equal by blast
          next
            case False
            then have f5: "¬(fst instr  {logic_type ANDs,logic_type ANDcc,logic_type ANDN,
            logic_type ANDNcc,logic_type ORs,logic_type ORcc,logic_type ORN,
            logic_type XORs,logic_type XNOR})"
              by auto
            then show ?thesis 
            proof (cases "fst instr  {shift_type SLL,shift_type SRL,shift_type SRA}")
              case True
              then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 
              apply dispath_instr_privilege_proof
              using shift_instr_low_equal by blast
            next
              case False
              then have f6: "¬(fst instr  {shift_type SLL,shift_type SRL,shift_type SRA})"
                by auto
              then show ?thesis 
              proof (cases "fst instr  {arith_type ADD,arith_type ADDcc,arith_type ADDX}")
                case True
                then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6
                apply dispath_instr_privilege_proof
                using add_instr_low_equal by blast
              next
                case False
                then have f7: "¬(fst instr  {arith_type ADD,arith_type ADDcc,arith_type ADDX})"
                  by auto
                then show ?thesis
                proof (cases "fst instr  {arith_type SUB,arith_type SUBcc,arith_type SUBX}")
                  case True
                  then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 
                  apply dispath_instr_privilege_proof
                  using sub_instr_low_equal by blast
                next
                  case False
                  then have f8: "¬(fst instr  {arith_type SUB,arith_type SUBcc,arith_type SUBX})"
                    by auto
                  then show ?thesis
                  proof (cases "fst instr  {arith_type UMUL,arith_type SMUL,arith_type SMULcc}")
                    case True
                    then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8
                    apply dispath_instr_privilege_proof
                    using mul_instr_low_equal by blast
                  next
                    case False
                    then have f9: "¬(fst instr  {arith_type UMUL,arith_type SMUL,
                      arith_type SMULcc})"
                      by auto
                    then show ?thesis 
                    proof (cases "fst instr  {arith_type UDIV,arith_type UDIVcc,arith_type SDIV}")
                      case True
                      then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9
                      apply dispath_instr_privilege_proof
                      using div_instr_low_equal by blast
                    next
                      case False
                      then have f10: "¬(fst instr  {arith_type UDIV,
                        arith_type UDIVcc,arith_type SDIV})"
                        by auto
                      then show ?thesis 
                      proof (cases "fst instr  {ctrl_type SAVE,ctrl_type RESTORE}")
                        case True
                        then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9 f10
                        apply dispath_instr_privilege_proof
                        using save_restore_instr_low_equal by blast
                      next
                        case False
                        then have f11: "¬(fst instr  {ctrl_type SAVE,ctrl_type RESTORE})"
                          by auto
                        then show ?thesis 
                        proof (cases "fst instr  {call_type CALL}")
                          case True
                          then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11
                          apply dispath_instr_privilege_proof
                          using call_instr_low_equal by blast                          
                        next
                          case False
                          then have f12: "¬(fst instr  {call_type CALL})" by auto
                          then show ?thesis
                          proof (cases "fst instr  {ctrl_type JMPL}")
                            case True
                            then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
                            apply dispath_instr_privilege_proof
                            using jmpl_instr_low_equal by blast
                          next
                            case False
                            then have f13: "¬(fst instr  {ctrl_type JMPL})" by auto
                            then show ?thesis 
                            proof (cases "fst instr  {ctrl_type RETT}")
                              case True
                              then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 
                                f11 f12 f13
                              apply dispath_instr_privilege_proof
                              using rett_instr_low_equal by blast
                            next
                              case False
                              then have f14: "¬(fst instr  {ctrl_type RETT})" by auto
                              then show ?thesis 
                              proof (cases "fst instr  {sreg_type RDY,sreg_type RDPSR,
                                sreg_type RDWIM, sreg_type RDTBR}")
                                case True
                                then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 
                                  f11 f12 f13 f14
                                apply dispath_instr_privilege_proof
                                using read_state_reg_low_equal by blast
                              next
                                case False
                                then have f15: "¬(fst instr  {sreg_type RDY,sreg_type RDPSR,
                                sreg_type RDWIM, sreg_type RDTBR})" by auto
                                then show ?thesis
                                proof (cases "fst instr  {sreg_type WRY,sreg_type WRPSR,
                                  sreg_type WRWIM, sreg_type WRTBR}")
                                  case True
                                  then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9 
                                    f10 f11 f12 f13 f14 f15 
                                  apply dispath_instr_privilege_proof
                                  using write_state_reg_low_equal by blast
                                next
                                  case False
                                  then have f16: "¬(fst instr  {sreg_type WRY,sreg_type WRPSR,
                                  sreg_type WRWIM, sreg_type WRTBR})" by auto
                                  then show ?thesis
                                  proof (cases "fst instr  {load_store_type FLUSH}")
                                    case True
                                    then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 f9 
                                      f10 f11 f12 f13 f14 f15 f16 
                                    apply dispath_instr_privilege_proof
                                    using flush_instr_low_equal by blast
                                  next
                                    case False
                                    then have f17: "¬(fst instr  {load_store_type FLUSH})" by auto
                                    then show ?thesis 
                                    proof (cases "fst instr  {bicc_type BE,bicc_type BNE,
                                      bicc_type BGU,bicc_type BLE,bicc_type BL,bicc_type BGE,
                                      bicc_type BNEG,bicc_type BG,bicc_type BCS,bicc_type BLEU,
                                      bicc_type BCC,bicc_type BA,bicc_type BN}")
                                      case True
                                      then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 
                                        f9 f10 f11 f12 f13 f14 f15 f16 f17
                                      apply dispath_instr_privilege_proof
                                      using branch_instr_low_equal by blast
                                    next
                                      case False
                                      then show ?thesis using a1 f_no_traps f1 f2 f3 f4 f5 f6 f7 f8 
                                        f9 f10 f11 f12 f13 f14 f15 f16 f17
                                      apply dispath_instr_privilege_proof
                                      by (simp add: fail_def)
                                    qed
                                  qed
                                qed
                              qed
                            qed
                          qed
                        qed
                      qed
                    qed
                  qed
                qed
              qed
            qed
          qed
        qed
      qed
    qed
  qed
next
  case False
  then have "get_trap_set s1  {}  get_trap_set s2  {}" 
    using a1 by (simp add: low_equal_def get_trap_set_def)
  then show ?thesis using a1
  apply (simp add: dispatch_instruction_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def)
  apply (simp add: Let_def)
  by (simp add: return_def)
qed

lemma execute_instr_sub1_low_equal:
assumes a1: "low_equal s1 s2 
¬ snd (execute_instr_sub1 instr s1) 
¬ snd (execute_instr_sub1 instr s2) 
t1 = (snd (fst (execute_instr_sub1 instr s1))) 
t2 = (snd (fst (execute_instr_sub1 instr s2)))"
shows "low_equal t1 t2"
proof (cases "get_trap_set s1 = {}")
  case True
  then have "get_trap_set s1 = {}  get_trap_set s2 = {}"
    using a1 by (simp add: low_equal_def get_trap_set_def)
  then show ?thesis using a1
  apply (simp add: execute_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  apply (case_tac "fst instr  call_type CALL 
                fst instr  ctrl_type RETT 
                fst instr  ctrl_type JMPL 
                fst instr  bicc_type BE 
                fst instr  bicc_type BNE 
                fst instr  bicc_type BGU 
                fst instr  bicc_type BLE 
                fst instr  bicc_type BL 
                fst instr  bicc_type BGE 
                fst instr  bicc_type BNEG 
                fst instr  bicc_type BG 
                fst instr  bicc_type BCS 
                fst instr  bicc_type BLEU 
                fst instr  bicc_type BCC 
                fst instr  bicc_type BA  fst instr  bicc_type BN")
   apply clarsimp
   apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
   apply (simp add: case_prod_unfold)
   apply (simp add: low_equal_def)
   apply (simp add: cpu_reg_val_def write_cpu_def cpu_reg_mod_def)
   apply (simp add: simpler_modify_def return_def)
   apply (simp add: user_accessible_mod_cpu_reg mem_equal_mod_cpu_reg)
   apply clarsimp
  by (auto simp add: return_def)
next
  case False
  then have "get_trap_set s1  {}  get_trap_set s2  {}" 
    using a1 by (simp add: low_equal_def get_trap_set_def)
  then show ?thesis using a1
  apply (simp add: execute_instr_sub1_def)
  apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
  by (simp add: return_def)
qed

theorem non_interference_step: 
assumes a1: "(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
good_context s1 
get_delayed_pool s1 = []  get_trap_set s1 = {} 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
get_delayed_pool s2 = []  get_trap_set s2 = {} 
good_context s2 
low_equal s1 s2"
shows "t1 t2. Some t1 = NEXT s1  Some t2 = NEXT s2  
(((get_S (cpu_reg_val PSR t1)))::word1) = 0 
(((get_S (cpu_reg_val PSR t2)))::word1) = 0 
low_equal t1 t2"
proof -
  from a1 have "good_context s1  good_context s2" by auto
  then have "NEXT s1 = Some (snd (fst (execute_instruction () s1))) 
             NEXT s2 = Some (snd (fst (execute_instruction () s2)))"
       by (simp add: single_step)
  then have "t1 t2. Some t1 = NEXT s1  Some t2 = NEXT s2" 
       by auto
  then have f0: "snd (execute_instruction() s1) = False 
             snd (execute_instruction() s2) = False"
       by (auto simp add: NEXT_def case_prod_unfold)
  then have f1: "t1 t2. Some t1 = NEXT s1 
      Some t2 = NEXT s2 
      (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
      (((get_S (cpu_reg_val PSR t2)))::word1) = 0"
      using a1
      apply (auto simp add: NEXT_def case_prod_unfold)
       by (auto simp add: safe_privilege)
  then show ?thesis 
  proof (cases "exe_mode_val s1")
    case True
    then have f_exe0: "exe_mode_val s1" by auto
    then have f_exe: "exe_mode_val s1  exe_mode_val s2"
      proof -
        have "low_equal s1 s2" using a1 by auto
        then have "state_var s1 = state_var s2" by (simp add: low_equal_def)
        then have "exe_mode_val s1 = exe_mode_val s2" by (simp add: exe_mode_val_def)
        then show ?thesis using f_exe0 by auto
      qed
    then show ?thesis
    proof (cases "e. fetch_instruction (delayed_pool_write s1) = Inl e")
      case True
      then have f_fetch_error: "e. fetch_instruction (delayed_pool_write s1) = Inl e" by auto
      then have f_fetch_error2: "(e. fetch_instruction (delayed_pool_write s1) = Inl e)  
                 (e. fetch_instruction (delayed_pool_write s2) = Inl e)"
        proof -
          have "cpu_reg s1 = cpu_reg s2" 
            using a1 by (simp add: low_equal_def)
          then have "cpu_reg_val PC s1 = cpu_reg_val PC s2" 
            by (simp add: cpu_reg_val_def)
          then have "cpu_reg_val PC s1 = cpu_reg_val PC s2 
                     (((get_S (cpu_reg_val PSR (delayed_pool_write s1))))::word1) = 0 
                     (((get_S (cpu_reg_val PSR (delayed_pool_write s2))))::word1) = 0"
            using a1 
            by (auto simp add: empty_delayed_pool_write_privilege)  
          then show ?thesis using a1 f_fetch_error
          apply (simp add: fetch_instruction_def)
          apply (simp add: Let_def)         
          apply clarsimp
          apply (case_tac "uint (3 AND cpu_reg_val PC (delayed_pool_write s1)) = 0")
           apply auto
           apply (case_tac "fst (memory_read 8 (cpu_reg_val PC (delayed_pool_write s1)) 
           (delayed_pool_write s1)) = None")
            apply auto
            apply (simp add: case_prod_unfold)
            using a1 apply (auto simp add: mem_read_delayed_write_low_equal)
           apply (simp add: case_prod_unfold)
           using a1 apply (auto simp add: mem_read_delayed_write_low_equal)
          apply (simp add: delayed_pool_write_def)
          by (simp add: Let_def get_delayed_write_def)
        qed
      then show ?thesis 
      proof (cases "exe_mode_val s1")
        case True
        then have "exe_mode_val s1  exe_mode_val s2" using exe_mode_low_equal a1 by auto
        then show ?thesis using f1
        apply (simp add: NEXT_def execute_instruction_def)
        apply (simp add: bind_def h1_def h2_def Let_def simpler_gets_def)
        using a1 apply clarsimp
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: simpler_modify_def)
        using f_fetch_error2 apply clarsimp
        apply (simp add: raise_trap_def simpler_modify_def return_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: return_def simpler_modify_def)
        apply (simp add: raise_trap_def simpler_modify_def return_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: return_def)
        apply (simp add: delayed_pool_write_def get_delayed_write_def Let_def)
        apply (simp add: low_equal_def)
        apply (simp add: add_trap_set_def)
        apply (simp add: cpu_reg_val_def)
        apply clarsimp
        by (simp add: mem_equal_mod_trap user_accessible_mod_trap)       
      next
        case False
        then have "¬ (exe_mode_val s1)  ¬ (exe_mode_val s2)" 
          using exe_mode_low_equal a1 by auto
        then show ?thesis using f1
        apply (simp add: NEXT_def execute_instruction_def)
        apply (simp add: bind_def h1_def h2_def Let_def simpler_gets_def)
        using a1 apply clarsimp
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        by (simp add: return_def)
      qed
    next
      case False
      then have f_fetch_suc: "(v. fetch_instruction (delayed_pool_write s1) = Inr v)" 
        using fetch_instr_result_1 by auto
      then have "(v. fetch_instruction (delayed_pool_write s1) = Inr v 
                      fetch_instruction (delayed_pool_write s2) = Inr v)"
        proof -
          have "cpu_reg s1 = cpu_reg s2" 
            using a1 by (simp add: low_equal_def)
          then have "cpu_reg_val PC s1 = cpu_reg_val PC s2" 
            by (simp add: cpu_reg_val_def)
          then have "cpu_reg_val PC s1 = cpu_reg_val PC s2 
                     (((get_S (cpu_reg_val PSR (delayed_pool_write s1))))::word1) = 0 
                     (((get_S (cpu_reg_val PSR (delayed_pool_write s2))))::word1) = 0"
            using a1 
            by (auto simp add: empty_delayed_pool_write_privilege)  
          then show ?thesis using a1 f_fetch_suc
          apply (simp add: fetch_instruction_def)
          apply (simp add: Let_def) 
          apply clarsimp
          apply (case_tac "uint (3 AND cpu_reg_val PC (delayed_pool_write s1)) = 0")
           apply auto
           apply (case_tac "fst (memory_read 8 (cpu_reg_val PC (delayed_pool_write s1)) 
           (delayed_pool_write s1)) = None")
            apply auto
            apply (simp add: case_prod_unfold)
           using a1 apply (auto simp add: mem_read_delayed_write_low_equal)
           apply (simp add: case_prod_unfold)
           using a1 apply (auto simp add: mem_read_delayed_write_low_equal)
          apply (simp add: delayed_pool_write_def)
          by (simp add: Let_def get_delayed_write_def)
        qed
      then have "(v. fetch_instruction (delayed_pool_write s1) = Inr v 
                      fetch_instruction (delayed_pool_write s2) = Inr v 
                      ¬ (e. (decode_instruction v) = Inl e))"
        using dispatch_fail f0 a1 f_exe by auto
      then have f_fetch_dec: "(v. fetch_instruction (delayed_pool_write s1) = Inr v 
                      fetch_instruction (delayed_pool_write s2) = Inr v 
                      (v1. (decode_instruction v) = Inr v1))"
        using decode_instr_result_4 by auto      
      then show ?thesis 
      proof (cases "annul_val (delayed_pool_write s1)")
        case True
        then have "annul_val (delayed_pool_write s1)  annul_val (delayed_pool_write s2)"
          using a1 
          apply (simp add: low_equal_def)
          by (simp add: delayed_pool_write_def get_delayed_write_def annul_val_def)
        then show ?thesis using a1 f1 f_exe f_fetch_dec
        apply (simp add: NEXT_def execute_instruction_def)
        apply (simp add: exec_gets return_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: simpler_modify_def)
        apply clarsimp
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: case_prod_unfold)
        apply (simp add: write_cpu_def cpu_reg_val_def set_annul_def)
        apply (simp add: simpler_modify_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: write_cpu_def cpu_reg_val_def set_annul_def)
        apply (simp add: simpler_modify_def)
        apply (simp add: cpu_reg_mod_def annul_mod_def)
        apply (simp add: delayed_pool_write_def get_delayed_write_def)
        apply (simp add: write_annul_def)
        apply clarsimp
        apply (simp add: low_equal_def)
        apply (simp add: user_accessible_annul mem_equal_annul)
        by (metis)        
      next
        case False
        then have "¬ annul_val (delayed_pool_write s1) 
          ¬ annul_val (delayed_pool_write s2)"
          using a1 apply (simp add: low_equal_def)
          apply (simp add: delayed_pool_write_def get_delayed_write_def)
          by (simp add: annul_val_def)
        then show ?thesis using a1 f1 f_exe f_fetch_dec
        apply (simp add: NEXT_def execute_instruction_def)
        apply (simp add: exec_gets return_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: simpler_modify_def)
        apply clarsimp
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: case_prod_unfold)
        apply (case_tac "snd (execute_instr_sub1 (a, b)
                   (snd (fst (dispatch_instruction (a, b)
                               (delayed_pool_write s1))))) 
             snd (dispatch_instruction (a, b) (delayed_pool_write s1))")
         apply auto
        apply (case_tac "snd (execute_instr_sub1 (a, b)
                   (snd (fst (dispatch_instruction (a, b)
                               (delayed_pool_write s2))))) 
             snd (dispatch_instruction (a, b) (delayed_pool_write s2))")
         apply auto
        apply (simp add: simpler_modify_def)
        apply (simp add: simpler_gets_def bind_def h1_def h2_def Let_def)
        apply (simp add: case_prod_unfold)
        apply (simp add: delayed_pool_write_def get_delayed_write_def)
        by (meson dispath_instr_low_equal dispath_instr_privilege execute_instr_sub1_low_equal)        
      qed
    qed
  next
    case False
    then have f_non_exe: "exe_mode_val s1 = False" by auto
    then have "exe_mode_val s1 = False  exe_mode_val s2 = False"        
      proof -
        have "low_equal s1 s2" using a1 by auto
        then have "state_var s1 = state_var s2" by (simp add: low_equal_def)
        then have "exe_mode_val s1 = exe_mode_val s2" by (simp add: exe_mode_val_def)
        then show ?thesis using f_non_exe by auto
      qed
    then show ?thesis using f1 a1    
    apply (simp add: NEXT_def execute_instruction_def)
    by (simp add: simpler_gets_def bind_def h1_def h2_def Let_def return_def)
  qed
qed

function (sequential) SEQ:: "nat  ('a::len) sparc_state  ('a) sparc_state option"
where "SEQ 0 s = Some s"
|"SEQ n s = (
  case SEQ (n-1) s of None  None
  | Some t  NEXT t
)"
by pat_completeness auto
termination by lexicographic_order

lemma SEQ_suc: "SEQ n s = Some t  SEQ (Suc n) s = NEXT t"
apply (induction n)
 apply clarsimp
by (simp add: option.case_eq_if)

definition user_seq_exe:: "nat  ('a::len) sparc_state  bool" where
"user_seq_exe n s  i t. (i  n  SEQ i s = Some t) 
  (good_context t  get_delayed_pool t = []  get_trap_set t = {})"

text ‹NIA is short for non-interference assumption.›
definition "NIA t1 t2  
    (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR t2)))::word1) = 0 
    good_context t1  get_delayed_pool t1 = []  get_trap_set t1 = {} 
    good_context t2  get_delayed_pool t2 = []  get_trap_set t2 = {} 
    low_equal t1 t2"

text ‹NIC is short for non-interference conclusion.›
definition "NIC t1 t2  (u1 u2. Some u1 = NEXT t1  Some u2 = NEXT t2  
    (((get_S (cpu_reg_val PSR u1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR u2)))::word1) = 0 
    low_equal u1 u2)"

lemma NIS_short: "t1 t2. NIA t1 t2  NIC t1 t2"
apply (simp add: NIA_def NIC_def)
using non_interference_step by auto

lemma non_interference_induct_case_sub1:
assumes a1: "(t1. Some t1 = SEQ n s1 
    (t2. Some t2 = SEQ n s2 
    NIA t1 t2))"
shows "(t1. Some t1 = SEQ n s1 
    (t2. Some t2 = SEQ n s2 
    NIA t1 t2 
    NIC t1 t2))"
using NIS_short
using assms by auto 

lemma non_interference_induct_case: 
assumes a1: 
"((i t. i  n  SEQ i s1 = Some t 
                 good_context t  get_delayed_pool t = []  get_trap_set t = {}) 
          (i t. i  n  SEQ i s2 = Some t 
                 good_context t  get_delayed_pool t = []  get_trap_set t = {}) 
          (t1. Some t1 = SEQ n s1 
               (t2. Some t2 = SEQ n s2 
                     (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR t2)))::word1) = 0  low_equal t1 t2))) 
(i t. i  Suc n  SEQ i s1 = Some t 
               good_context t  get_delayed_pool t = []  get_trap_set t = {}) 
         (i t. i  Suc n  SEQ i s2 = Some t 
               good_context t  get_delayed_pool t = []  get_trap_set t = {})"
shows "t1. Some t1 = (case SEQ n s1 of None  None | Some x  NEXT x) 
              (t2. Some t2 = (case SEQ n s2 of None  None | Some x  NEXT x) 
                    (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR t2)))::word1) = 0  low_equal t1 t2)"
proof -
  from a1 have f1: "((i t. i  n  SEQ i s1 = Some t 
  good_context t  get_delayed_pool t = []  get_trap_set t = {}) 
  (i t. i  n  SEQ i s2 = Some t 
  good_context t  get_delayed_pool t = []  get_trap_set t = {}))"
  by (metis le_SucI)
  then have f2: "(t1. Some t1 = SEQ n s1 
    (t2. Some t2 = SEQ n s2 
    (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR t2)))::word1) = 0 
    low_equal t1 t2))"
  using a1 by auto
  then have f3: "(t1. Some t1 = SEQ n s1 
    (t2. Some t2 = SEQ n s2 
    NIA t1 t2))"
  using f1 NIA_def by (metis (full_types) dual_order.refl)  
  then have "(t1. Some t1 = SEQ n s1 
    (t2. Some t2 = SEQ n s2 
    NIA t1 t2 
    NIC t1 t2))"
  using non_interference_induct_case_sub1 by blast
  then have "(t1. Some t1 = SEQ n s1 
    (t2. Some t2 = SEQ n s2 
    ((((get_S (cpu_reg_val PSR t1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR t2)))::word1) = 0 
    good_context t1  get_delayed_pool t1 = []  get_trap_set t1 = {} 
    good_context t2  get_delayed_pool t2 = []  get_trap_set t2 = {} 
    low_equal t1 t2) 
    (u1 u2. Some u1 = NEXT t1  Some u2 = NEXT t2  
    (((get_S (cpu_reg_val PSR u1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR u2)))::word1) = 0 
    low_equal u1 u2)))"
  using NIA_def NIC_def by fastforce
  then show ?thesis
  by (metis option.simps(5))
qed

lemma non_interference_induct_case_sub2: 
assumes a1: 
"(user_seq_exe n s1 
          user_seq_exe n s2 
          (t1. Some t1 = SEQ n s1 
               (t2. Some t2 = SEQ n s2 
                     (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR t2)))::word1) = 0  low_equal t1 t2))) 
user_seq_exe (Suc n) s1 
         user_seq_exe (Suc n) s2"
shows "t1. Some t1 = (case SEQ n s1 of None  None | Some x  NEXT x) 
              (t2. Some t2 = (case SEQ n s2 of None  None | Some x  NEXT x) 
                    (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
    (((get_S (cpu_reg_val PSR t2)))::word1) = 0  low_equal t1 t2)"
using a1
by (simp add: non_interference_induct_case user_seq_exe_def)

theorem non_interference:
assumes a1: 
"(((get_S (cpu_reg_val PSR s1)))::word1) = 0 
good_context s1 
get_delayed_pool s1 = []  get_trap_set s1 = {} 
(((get_S (cpu_reg_val PSR s2)))::word1) = 0 
get_delayed_pool s2 = []  get_trap_set s2 = {} 
good_context s2 
user_seq_exe n s1  user_seq_exe n s2 
low_equal s1 s2"
shows "(t1 t2. Some t1 = SEQ n s1  Some t2 = SEQ n s2 
  (((get_S (cpu_reg_val PSR t1)))::word1) = 0 
  (((get_S (cpu_reg_val PSR t2)))::word1) = 0 
  low_equal t1 t2)"
using a1
apply (induction n)
 apply (simp add: user_seq_exe_def)
apply clarsimp
by (simp add: non_interference_induct_case_sub2)

end

Theory Sparc_Init_State

(*
 * Copyright 2016, NTU
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * Author: Zhe Hou.
 *)

theory Sparc_Init_State
imports Main Sparc_State Sparc_Types Sparc_Execution
begin

definition emp_cpu_reg :: "cpu_context" where
"emp_cpu_reg r  0"

definition emp_user_reg :: "word5  window_context" where
"emp_user_reg ws w5  0"

definition emp_sys_reg :: "sys_context" where
"emp_sys_reg r  0"

definition emp_mem :: "mem_context" where
"emp_mem asi add  None"

definition init_mmu:: "MMU_state" where
"init_mmu  mmu_setup"

definition emp_cpu_cache :: "cpu_cache" where
"emp_cpu_cache  dcache = empty_cache,icache = empty_cache"

definition emp_dw_pool :: "delayed_write_pool" where
"emp_dw_pool  []"

definition emp_bbyte :: "virtua_address  bool" where
"emp_bbyte add  False"

definition emp_bword :: "virtua_address  bool" where
"emp_bword add  False"

text ‹ANNUL = False, RESET_TRAP = False, EXECUTE_MODE = True,
  RESET_MODE = False, ERROR_MODE = False.›
definition init_svar :: "sparc_state_var" where
"init_svar  annul=False,resett=False,exe=True,
reset=False,err=False,ticc=(0b0000000::word7),
itrpt_lvl=(0b000::word3),st_bar=False,
atm_ldst_byte=emp_bbyte, atm_ldst_word=emp_bword"

definition emp_trap :: "Trap set" where
"emp_trap  {}"

definition emp_state :: "leon3_state" where
"emp_state  cpu_reg=emp_cpu_reg, user_reg=emp_user_reg, sys_reg=emp_sys_reg,
mem=emp_mem, mmu=init_mmu, cache=emp_cpu_cache, dwrite=emp_dw_pool,
state_var=init_svar,
traps=emp_trap, undef=False"

text ‹PSR.ET = 1, PS= 1, S = 1, in init_state.
  By default, CWP = 0.
  icc = 0000, ver = 0011, impl = 1111.
  This is the default setting of LEON3.›
definition init_state0 :: "leon3_state" where
"init_state0 
  let s1 = cpu_reg_mod (0b11110011000000000000000011100000) PSR emp_state in
  cpu_reg_mod (0b00000000000000000000000000000010) TBR s1"

text ‹Initialise PC and nPC.
  And initialise r[14] in window 0 to 0x4ffffff0,
  according to the LEON3 setup.›
definition init_state1 :: "leon3_state" where
"init_state1 
  let s1 = cpu_reg_mod (0b01000000000000000000000000000000) PC init_state0;
      s2 = cpu_reg_mod (0b01000000000000000000000000000100) nPC s1
  in
  user_reg_mod (0x4ffffff0) 0 (14) s2
  ⌦‹s1›
"

text ‹Initialise the memory address
  0b01000000000000000000000000000000
  and the following ones
  with an example sequence of instructions.›
definition init_state2 :: "leon3_state" where
"init_state2 
      ― ‹ld r1 + r2 to r3›
  let s1 = mem_mod_w32 8 (0b01000000000000000000000000000000) (0b1111)
           (0b11000110000000000100000101000010) init_state1;
      ― ‹ld r5 + r6 to r4›
      s2 = mem_mod_w32 8 (0b01000000000000000000000000000100) (0b1111)
           (0b11001000000000010100000101000110) s1;
      ― ‹add r3 r4 to r8›
      s3 = mem_mod_w32 8 (0b01000000000000000000000000001000) (0b1111)
           (0b10010000000000001100000000000100) s2;
      ― ‹st r8 to address at r1 + r2›
      s4 = mem_mod_w32 8 (0b01000000000000000000000000001100) (0b1111)
           (0b11010000001000000100000101000010) s3;
      ― ‹ld r1 + r2 to r9›
      s5 = mem_mod_w32 8 (0b01000000000000000000000000010000) (0b1111)
           (0b11010010000000000100000101000010) s4
  in
  s5
"

definition init_state3:: "leon3_state" where
"init_state3 
  let curr_win = ucast (get_CWP (cpu_reg_val PSR init_state2));
      ― ‹r1 = 0x40000000›
      s1 = user_reg_mod (0b01000000000000000000000000000000)
           curr_win (0b00001) init_state2;
      ― ‹r2 = 0x1000›
      s2 = user_reg_mod (0b00000000000000000001000000000000)
           curr_win (0b00010) s1;
      ― ‹r5 = 0x40000000›
      s3 = user_reg_mod (0b01000000000000000000000000000000)
           curr_win (0b00101) s2;
      ― ‹r6 = 0x1004›
      s4 = user_reg_mod (0b00000000000000000001000000000100)
           curr_win (0b00110) s3;
      ― ‹0x40001000 = 1›
      s5 = mem_mod_w32 10 (0b01000000000000000001000000000000) (0b1111)
           (0b00000000000000000000000000000010) s4;
      ― ‹0x40001004 = 2›
      s6 = mem_mod_w32 10 (0b01000000000000000001000000000100) (0b1111)
           (0b00000000000000000000000000000100) s5
  in
  s6
"

end

Theory Sparc_Code_Gen

(*
 * Copyright 2016, NTU
 *
 * This software may be distributed and modified according to the terms of
 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
 * See "LICENSE_BSD2.txt" for details.
 *
 * Author: Zhe Hou.
 *)

theory Sparc_Code_Gen
imports Main Sparc_Execution Sparc_Init_State
begin

export_code init_state0 reset_mode_mod reset_mode_val
state_undef
seq_exec_leon3 in OCaml
module_name Sparc_seq file ‹sparc_seq›

end